Android ORM - GreenDAO - Simplifying DB access in your app

I am currently working on a new Android app, and as usual, it requires a considerable amount of DB interaction.  I would say DB interaction isn't that difficult in Android - you can create a few simple classes to setup your schema and then DAO functions for the various domain objects that you want to map to the DB.

Simple.

Just a pain in the ass.

Coming from working on a variety of Java type ORMs (Hibernate et al), this is really just all boiler plate that is painful to write, so this time around I decided to look for an Android ORM. The first result in google was greenDAO, which claims to be being used on over 10million installed apps (AppBrain lists it as being used on Pinterest and Zynga apps), which seemed like pretty good reason to take a look.


So I started taking a look at the code on GitHub - the first thing I noticed was that it wasn't a traditional ORM that I expected, really it's more of a code generator rather than an ORM like Hibernate - I was expecting to just define some POJO entities, maybe marked up with annotations or config  that did all the magic - but what is actually going on is you have to create a "generator" project that defines your domain entities and then that produces several DAO and domain object classes that can be generated directly into your normal Android app.

Does generated code always suck?

I saw the words generator and alarm bells started to ring - I have worked with and on projects that generate code and it so often seems to have descended in to pain - often needing to slightly tweak the generated code, which then results in painful re-generation or just walking away from the generator altogether and being left with having to manually maintain generated code.

However, I had a look at the generated code and it was actually quite nice - not that different from if I had written it, and what swung it for me was the performance. I had briefly pondered building a lightweight ORM for Android more in the style of Hibernate (I love an annotation), but then I thought on the performance impact - reading annotations on POJOs at runtime - even if cached - the performance footprint was likely to be pretty big would suck for people with older/less powerful devices.


So actually, removing the pain of having to create all the DAO objects etc, whilst not having a prohibitive performance impact made this a pretty strong choice.


Let's get down to business, don't got no time to play around, what is this..

So lets have a look at how we generate the code - its actually relatively easily to programmatic-ly configure your entities for generation.





The above is an example of how you can configure two simple domain entities (which will map to a table - this is like defining a Hibernate @Entity POJO). In the above simplified, hypothetical design, we have two real domain entities "Email" and "People" - emails can be sent to multiple people, and people can recieve multiple emails.

As you can see, we define a very simple People entity. and then programatically add three columns - an ID, a name and an email address. Simple - and as you can see(or imagine) the API provides programatic constructs to configure not null, column types, etc.


All in all, so far it has been a good experience - It has removed a certain amount of the pain from developing the DAO/DB layer boiler plate stuff and let me concentrate on the important stuff about the app. However, one gripe I do have is that it doesn't currently support modelling of many-to-many relationships - the best you can do is create an entity to model what is effectively a join table, then have a one-to-many relationship from that to either side of your "real" many-to-many relationship.

Again, in the above example, we try manage the many-to-many relationship between people and emails (emails can have may people recipients, and people can be recipients to many emails). As mentioned - we have had to model this join explicitly with an EmailPeople entity, and then add the OneToMany relationship between People/Email to our new Join entity.  This is no real headache to do, but is undoubtedly going to be a performance hit - The underlying code will undoubtedly be being cleverly efficient in retrieving all the EmailPeople entities for a given email (assuming attempting to get all recipients to an email) - but from that list we then need an efficient way to load all the People enties linked to that list of EmailPeople entites.
 

0 comments: