I've been trying to create a database where all the tables inherit a certain element in order to have to possibility to have meta-data.
there for I added in the model generator in all the table declarations this line:
public Entity addSuperEntity(Schema schema) {
Entity superEntity = schema.addEntity("superEntity");
superEntity.addIdProperty().primaryKey();
// SET RELATIONSHIP 1:m TO META DATA
}
public Entity addTable(Schema schema) {
Entity mEntity = schema.addEntity("MyEntity");
mEntity.setSuper("superEntity");
mEntity.addIdProperty().PrimaryKey();
// REST OF FIELDS
}
the question is:
now after I generated this to my Android project, how can I make sure that this still happens in real life? do I need to change anything now?
the official documentation doesn't have anything about inheritance.
Inheritance is supported for non-entity super classes using setSuperclass(String). An alternative is implementing interfaces using implementsInterface(String).
I updated the official docs with some details in the new section on inheritance and interfaces:
http://greendao-orm.com/documentation/modelling-entities/
Related
While using Room Persistence Library, I wonder why we have to explicitly specify the entities while creating a RoomDatabase as the entities are already annotated with #Entity annotation. I mean We could simply skip the entities attribute of the #Database annotation.
It's still useful. Sure we could remove it but:
Can't/convinent way to specify some the other things we can specify in that annotation as arguments in there.
It describes the intention, this is important. This means that other parts (tools/IDE) can check if this really is an Entity you are trying to fetch or if a mistake was made.
As a marker "interface", related to the previous point, but to simply communicate what it is and easily find them.
Tools/lib/frameworks might/probably need/want it as they can generate stuff/shadow classes/subclasses or such things. At least for analysis, related to first 1st and 2nd point as well.
For example see the EntityProcessor in the source for Room.
I am trying to implement DBFlow for the first time and I think I might just not get it. I am not an advanced Android developer, but I have created a few apps. In the past, I would just create a "database" object that extends SQLiteOpenHelper, then override the callback methods.
In onCreate, once all of the tables have been created, I would populate any lookup data with a hard-coded SQL string: db.execSQL(Interface.INSERT_SQL_STRING);. Because I'm lazy, in onUpgrade() and onDowngrade(), I would just DROP the tables and call onCreate(db);.
I have read through the migrations documentation, which not only seems to be outdated syntactically because "database =" has been changed to "databaseName =" in the annotation, but also makes no mention of migrating from no database to version "initial". I found an issue that claims that migration 0 can be used for this purpose, but I cannot get any migrations to work at this point.
Any help would be greatly appreciated. The project is # Github.
The answer below is correct, but I believe that this Answer and Question will soon be "deprecated" along with most third-part ORMs. Google's new Room Persistence Library (Yigit's Talk) will be preferred in most cases. Although DBFlow will certainly carry on (Thank You Andrew) in many projects, here is a good place to re-direct people to the newest "best practice" because this particular question was/is geared for those new to DBFlow.
The correct way to initialize the database (akin to the SQLiteOpenHelper's onCreate(db) callback is to create a Migration object that extends BaseMigration with the version=0, then add the following to the onCreate() in the Application class (or wherever you are doing the DBFlow initialization):
FlowManager.init(new FlowConfig.Builder(this).build());
FlowManager.getDatabase(BracketsDatabase.NAME).getWritableDatabase();
In the Migration Class, you override the migrate() and then you can use the Transaction manager to initialize lookup data or other initial database content.
Migration Class:
#Migration(version = 0, database = BracketsDatabase.class)
public class DatabaseInit extends BaseMigration {
private static final String TAG = "classTag";
#Override
public void migrate(DatabaseWrapper database) {
Log.d(TAG, "Init Data...");
populateMethodOne();
populateMethodTwo();
populateMethodThree();
Log.d(TAG, "Data Initialized");
}
To populate the data, use your models to create the records and the Transaction Manager to save the models via FlowManager.getDatabase(AppDatabase.class).getTransactionManager()
.getSaveQueue().addAll(models);
To initialize data in DBFlow all you have to do is create a class for your object models that extends BaseModel and use the #Table annotation for the class.
Then create some objects of that class and call .save() on them.
You can check the examples in the library's documentation.
I'm currently into evaluating GreenDAO for my application. I'm facing the following problem.
My app consists of several modules (seperated in packages, e.g. "com.example.app.results", "com.example.app.synchronization"). Some of them have no dependencies, some of them have dependencies on other modules (e.g. synchronization has a dependency on results, whereas results has no dependency).
What I would like to model is the following:
Module results has Entity MyResult (attributes: name, value).
Module synchronization has Entity MyResultSynchronization (attributes: MyResult (reference), date).
final Schema schema = new Schema(1, "com.example.app");
final Entity myresult = schema.addEntity("results.MyResult");
final Property myresultId = myresult.addIdProperty().getProperty();
myresult.addStringProperty("name");
myresult.addStringProperty("value");
final Entity myResultSynchronization = schema.addEntity("synchronization.MyResultSynchronization");
myResultSynchronization.addIdProperty();
myResultSynchronization.addDateProperty("date");
myResultSynchronization.addToOne(myresult, myresultId);
but - $entityPackage.$name does not what I expected it to do (neither did $package\$name ;-)).
My question is: Am I forced to have all entities of my app in a single package? Is what I'm trying to do feasible by creating multiple Schemas - but than again, is it possible to use the relate-feature between two (or more) schemas? What is the "right" way to do it? (Is there one?)
Indeed all entities have to be in the same package.
Normally you use a structure like
com.example.myapp.data
Where you put everything for managing your database, especially your entity classes. Inside you can let greendao create a dao package where it will put everything needed to access your data (base).
Of course you can enforce your naning schema by making multiple sxhemas in greendao. But the schemas will be independent: They won't use the same database and you won't be able to link them together with toOne () for example.
If you still want to use your naming schema you can generate everything to an intermediate package and move them to your desired packages manually. But you would have to repeat this upon every change to your database schema, which is more often than one may think at first.
I'm using GreenDao and creating a core function that help you to update some values of an entity, and if the entity is not in the database then it also inserting it. The problem is that I'm always getting the cached copy of the entity, I know that GreenDao manage some simple cache and I would like to have the ability bypass it. does anyone knows how I can query right from the database?
This doesn't work
.Dao().queryBuilder().where(comDao.Properties.Id.eq(id)).build().listLazyUncached();
GreenDao indeed has Inner caching mechanism in its daoCore.jar sources.
You can disable the caching easily by searching for the code that put() and get() entities from the cache.
which is a: HashMap<? extends AbstractDao>.
Then generate MyDaoCore.jar and add it to your project.
Secondly, in order to update or insert and entity (without replacing it entirely) you need to implement the following pseudo code. I'm sorry that I'm not adding the actual code, I solved it long time ago.
public void insertOrUpdate(List<? extends AbstractDao> entities){
List<Entity> toInsert;
List<Entity> toUpdate;
for (Entity e : entities)
{
if( e.inDatabase() )
toUpdate.add(e);
else
toInsert.add(e);
}
Dao.updateAll(toUpdate);
Dao.insertAll(toInsert);
}
Edit 1:
You can use IN statement in order to get all the ids of an entity in only one query like this:
.where(Dao.Properties.Id.in(ids)).build().list();
I'm pretty new to Android development in general, and I've never even used greenDAO. But after spending a lot of time working on my generator class (Where I model my entities), I was finally able to produce something that looked similar to the example given on GitHub.
import de.greenrobot.daogenerator.DaoGenerator;
import de.greenrobot.daogenerator.Entity;
import de.greenrobot.daogenerator.Property;
import de.greenrobot.daogenerator.Schema;
import de.greenrobot.daogenerator.ToMany;
public class simbalDAOgen {
public static void main(String[] args) throws Exception {
Schema schema = new Schema(1, "com.bkp.simbal"); //Schema(Int version, String package name)
addCBTrans(schema); //Add the entities to the schema
new DaoGenerator().generateAll(schema, "../Simbal/src-gen", "../Simbal/src-test"); //Generate DAO files
}
private static void addCBTrans(Schema schema){
Entity checkbook = schema.addEntity("Checkbook");
checkbook.addIdProperty();
checkbook.addStringProperty("name").notNull();
checkbook.addDateProperty("dateModified");
checkbook.addStringProperty("balance"); // Use a string property because BigDecimal type should be used for currency
Entity transaction = schema.addEntity("Transaction");
transaction.setTableName("TRANS"); // "TRANSACTION" is a reserved SQLite keyword
transaction.addIdProperty();
transaction.addStringProperty("name");
transaction.addStringProperty("category");
Property transDate = transaction.addDateProperty("date").getProperty();
transaction.addStringProperty("amount"); // Again use string for BigDecimal type
transaction.addStringProperty("notes");
Property cbName = transaction.addStringProperty("cb").notNull().getProperty(); //What checkbook the transaction is in
ToMany cbToTrans = checkbook.addToMany(transaction, cbName); //Actually ties the transactions to their correct checkbooks
cbToTrans.setName("Transactions");
cbToTrans.orderAsc(transDate);
}
}
I then ran the code as a java application to generate my DAO files, just like the documentation on greenDAO says to. The files were successfully generated, however I did get this line in the console in Eclipse:
Warning to-one property type does not match target key type: ToMany 'Transactions' from Checkbook to Transaction
I'm really not sure if I need to be concerned since the files were generated. But what I don't understand is why there's mention of a "to-one" relation when I'm using a "to-many" relation, as can be seen in my code. (There can be many transaction entities in a checkbook entity, and I'm intending to use each checkbook entitys' name to tie the transactions to it.)
Do I need to go back and fix a part of my code? Please ask if I need to clarify anything, and thanks for your time!
After looking at the files generated for me by greenDAO, I've found the solution to my problem. It seems to me that the addToMany() method expects a Long property to be passed to it and I was using a String property. So I changed these two lines in my generator code:
Property cbName = transaction.addStringProperty("cb").notNull().getProperty();
ToMany cbToTrans = checkbook.addToMany(transaction, cbName);
to this:
Property checkbookId = transaction.addLongProperty("checkbookId").notNull().getProperty();
ToMany cbToTrans = checkbook.addToMany(transaction, checkbookId);
which solved my problem. I was under the impression I could use any type of property to tie the transactions to the checkbook, so I was trying the use the checkbook name.
it seems to be GreenDao only accepts type Long as foreign key