GreenDAO generated entities / name package convention - android

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.

Related

Class doesn't exist in current schema after being added to migration

I've been struggling performing a simple migration. What I just want to achieve is add a new Class in realm.
The code below is inside a method that is called inside onCreate.
Realm.init(this)
val config = RealmConfiguration.Builder()
.name("db_name")
.schemaVersion(5L)
.migration { realm, oldVersion, newVersion ->
val schema = realm.schema
var _oldVersion = oldVersion
if (_oldVersion == 4L) {
if (schema.contains(XModel::class.java.simpleName))
schema.remove(XModel::class.java.simpleName)
if (!schema.contains(XModel::class.java.simpleName))
schema.create(XModel::class.java.simpleName)
.addField(XModel::id.name, Long::class.javaPrimitiveType,
FieldAttribute.PRIMARY_KEY)
...
.addField(XModel::N.name, Int::class.javaPrimitiveType)
_oldVersion += 1
}
}
.build()
Realm.setDefaultConfiguration(config)
As what the title suggest, the new class in the schema was created inside the migration object, but when I try to access it in other parts of the application using a realm query or a simple call to schema.get("XModel") it will throw an error XModel doesn't exist in current schema. Any comment will really help. Thank you...
Edit:
Additional information. I have 2 realm objects, each are in different android modules, one module is dependent to the other. I somehow have some progress, now Im a bit confuse, do I need to declare 2 configurations? Then it would mean 2 realm instance? How to switch from both, I want to merge them into 1 realm.
Edit2:
Another clarification about realm. If you have 2 android modules, each of them using realm, will they have different realm even if in the realm configuration they have the same name?
Background
I want to give you a background of what im doing because I think its needed to fully understand my case.
Originally I only have one module, but then after refactoring and also because of future apps to be develop, I need to pull out the common classes from the existing module and put it in a separate lower-level module that the future apps can depend on. This new lower-level module will also be responsible for most of the data layer, so realm was transferred to this module. But I can't just ignore the realm of the existing app because some users might already populated it, and I need to transfer those data to the new database.

Why do we have to explicitly specify the entities while creating a Room Database as the entities are already annotated?

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.

Why are Hibernate/Jackson libraries required by my app?

I created a simple Web Server which use Hibernate to store entities on a MySQL database. Also, as you can expect, it shares some libraries with the clients in the <...>.shared> package to access various resources. Among them, there are the POJO classes, annotated with both Hibernate and Jackson annotations. This is an example of a POJO class.
#JsonInclude(Include.NON_NULL)
#Entity
#Table(name = "user", uniqueConstraints =
{ #UniqueConstraint(columnNames = "email"),
#UniqueConstraint(columnNames = "nick") })
public class User implements java.io.Serializable, RecognizedServerEntities
{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer userId;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "threadAuthor",
orphanRemoval = false)
#Cascade({ CascadeType.SAVE_UPDATE })
private Set<Thread> userThreads = new HashSet<Thread>(0);
}
Now, I'm trying to create an android app that simply use these shared classes: the app doesn't need to know anything about Hibernate, Javax.persistence and maybe even Jackson annotations.
However, when I create a new Android project, it requires a lot of libraries.
74K hibernate-commons-annotations-4.0.5.Final.jar
5,1M hibernate-core-4.3.6.Final.jar
38K jackson-annotations-2.4.0.jar
221K jackson-core-2.4.3.jar
1,1M jackson-databind-2.4.3.jar
180K javax.persistence_2.1.0.v201304241213.jar
714K org.restlet.jar
55K shared.jar
Problem is that they greatly magnify the app size and slow down the development process, because I have to enable Multidex support.
So, how can I solve?
I can think of some solutions:
Change the shared classes in some way to not expose the annotations. Is it a viable solution? How can I efficiently do this?
Use ProGuard. I don't know if it's really a solution because I don't know anything about this tool, but for what I've read it could help to delete classes that aren't used at all in the project.
EDIT: I partially worked around the problem extracting only required casses from hibernate-core-4.3.6.Final.jar, which is the greatest libraries. Still looking for most elegant solutions.
If you think of your application as having layers, you are currently using the same classes across the data access and view layers.
Your database isn't interested in the Jackson annotations, and your Android client isn't interested in the Hibernate annotations.
Two different approaches that I have seen for this are:
- have a parallel 'view' layer representation of your objects that has the Jackson annotations which your application will populate by mapping from your Hibernate annotated data access layer
OR
- have your client application not share the classes of the server application. It parses the JSON and maps the structures into your own client specific model.
These approaches are equivalent, but just vary by where the mapping takes place.

greenDAO generator gives console error that doesn't make sense

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

how to implement table inheritance in GreenDao

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/

Categories

Resources