Comparing android ORM libraries - GreenDAO vs Ormlite

So finally I've found some time to play with the GreenDAO and Ormlite. Recent weeks were quite busy for me and I couldn't find time to write the comparison I promised but now I will try to at least give some first use impression.

First thing that I've checked when comparing the both libs were the dependencies they introduce to the project. GreenDAO only requires one additional jar file, which is approx 54 KB in size. On contrary Ormlite requires two additional jar files to be included - they are 37 KB and 245 KB - that's much much more than in case of GreenDAO and way too much for small projects. It might be less important for big projects but for small projects it's definetelly too big. But hey - size doesn't matter they say ;).

First steps

Both libraries have a different approach to data objects and DAO's. GreenDAO is taking the code generation approach while the Ormlite is using good old annotations. I'm not specifically oriented toward one of the solutions - they both seems to be fine for me. So, let's made a quick comparison of both approaches.

Setting up the GreenDAO

If you would like to use GreenDAO then in order to generate the data classes and DAO's you need to write one additional app that will generate the required code.

        Schema schema = new Schema(1, "eu.softwareworkshop.android.greendaoexample");

        Entity _project = schema.addEntity("Project");
        _project.addIdProperty();
        _project.addStringProperty("name").notNull();
        _project.addStringProperty("description");
        _project.addDateProperty("createdAt");
        _project.addIntProperty("priority");
        _project.addDateProperty("due");
        
        Entity _tasks = schema.addEntity("Task");
        _tasks.addIdProperty();
        _tasks.addStringProperty("name").notNull();
        _tasks.addStringProperty("description");
        _tasks.addDateProperty("createdAt");
        _tasks.addIntProperty("priority");
        _tasks.addDateProperty("due");
        Property projectId = _tasks.addLongProperty("projectId").notNull().getProperty();
        
        _tasks.addToOne(_project, projectId);
        
        ToMany projecttasks = _project.addToMany(_tasks, projectId);
        
        new DaoGenerator().generateAll(schema, "../../../Example/src-gen");

 

that's the example code for creating the Project and Task entities. generateAll will generate the code in the given location - most likely it will be folder in the main android project.  This code will generate the following files.

DaoMaster.java
DaoSession.java
Project.java
ProjectDao.java
Task.java
TaskDao.java

DaoMaster and DaoSession are a general files that's going to be created every time and they will look almost the same - they are generally responsible for registering and creating the helpers and generated DAO's. . TaskDao.java and ProjectDao.java contains the code to create and drop the tables, bind and read the the entities. They are both extended from AbstractDao class which takes care of all the database operations. And finally we got Project.java and Task.java. They are our data objects which holds the properties we defined in our generator program as well as some db access methods like delete, save or refresh. Actually I'd rather prefer simple POJO approach rather than combined approach with data and db access methods but I can live with that one. It's not a big deal but I consider this to be a bad practice. There is absolutely no need to let objects update themselves. All they should contain is simple and untainted data.

So we have the GreenDAO set up initially. It's time to see how it get's done with the Ormline. It takes a bit more effort to set up the Ormlite. It's nicely laid out on their website but I will try to sum it up along with some thoughts on the process.

Setting up the Ormlite

First of all you have to create your own database helper class that will extend the OrmLiteSqliteOpenHeler class and override the following methods : onCreate, onUpgrade. In most cases that step will mean just taking the sample code from the example application and applying few changes. Because it's also a helper duty to return the appropriate daos then it also need to have code for this task. Example code that will return the DAO will look something along those lines

private Dao<Project, Integer> projectDao;

public Dao<Project, Integer> getProjectDao() throws SQLException {
        if (projectDao== null) {
            projectDao= getDao(Project.class);
        }
        return projectDao;
    }

When you have the helper ready it's time to use it in the Activity (or Service, or where you think it fits). Ormlite comes with few predefined base classes that you can use to make things easier. You can use OrmLiteBaseActivity<Helper> OrmLiteBaseService<Helper> , OrmLiteBaseListActivity<Helper> or OrmLiteBaseTabActivity<Helper>. If you decide to use those classes then getting the helper gets a bit easier and is basically using the getHelper() method. However if you would rather use your own base activity or you just don't want to use any of those for whatever reason, fear not - it will not make your life much harder. You will have to take care of helper maintenance by yourself. It will mean calling the OpenHelperManager.getHelper when creating the activity and OpenHelperManager.releaseHelper when closing the activity. And that's it. Nothing complicated.

At that point we are almost ready to start using the ORmlite. What's left is the data transport class configuration. As mentioned earlier Ormlite uses the annotations. Here is the example code:


@DatabaseTable
public class Project {
        @DatabaseField(generatedId = true)
        public Integer id;
        @DatabaseField
        public String name;
        @DatabaseField
        public String description;
        @DatabaseField
        public java.util.Date createdAt;
        @DatabaseField
        public Integer priority;
        @DatabaseField
        public java.util.Date due;
        @ForeignCollectionField
        public ForeignCollection<Task> tasks;
}

@DatabaseTable
public class Task {
        @DatabaseField(generatedId = true)
        public Integer id;
        @DatabaseField
        private String name;
        @DatabaseField
        private String description;
        @DatabaseField
        private java.util.Date createdAt;
        @DatabaseField
        private Integer priority;
        @DatabaseField
        private java.util.Date due;
        @DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = "project_id")
        public Project project;
}


The code is pretty obvious. We are creating two classes annotated as "DatabaseTable" - that will eventually create two database tables with all the fields annotated as "DatabaseField" included. There is also a relation defined between those two classes - the Task holds the reference to the Project and project has a collection of Tasks.

At this point we have most of the setup wrapped up and can start making some db calls.

Accessing the database

Accessing the database in both libraries is very easy. Both libraries grant very similiar set of methods. Of course they are named differently but give almost the same set of features.

Accessing the database using GreenDAO

GreenDAO requires few more additional steps before it will let us make the query.  We have to first create the DevOpenHelper, then obtain the SqLiteDatabase object. Then we pass this object to constructor of the DaoMaster, from DaoMaster we get the SaoSession and then eventually our final dao. In code it looks like that.

 DevOpenHelper helper = new DevOpenHelper(ctx, "swtasks-db", null);
 SQLiteDatabase db = helper.getWritableDatabase();
 DaoMaster daoMaster = new DaoMaster(db);
 DaoSession daoSession = daoMaster.newSession();
                
 TaskDao cdao = daoSession.getTaskDao();
 ProjectDao pdao =  daoSession.getProjectDao();

Now we can try to create an example project and example task.

 Project p = new Project();
 p.setName("GreenDAO project");
 p.setDescription("Example DAO project");
                
 Task t = new Task();
 t.setName("First task");
 t.setDescription("First task description");
 cdao.insert(t);
               
 p.getTask().add(t);
 pdao.insert(p);

That code will create the two entries in the database, and will also create the relation between the project and the task.

Getting the entities from the database is also very simple.

//to get the specified entity
Task t = cdao.load(id);
//to get all the entities
List<Task> allTasks = cdao.loadAll()

There are of course some more advanced queryinig mechnisms. We can use Query and QueryBuilder to run more complicated calls to the database, but I will describe it later.

Accessing the database using Ormlite

Accessing the database in the Ormlite is also very easy and strightforward. Assuming you are not using one of the predefined activity classes, first what you have to do is to obtain the database helper. Then you use the helper to get the appropriate dao, and finally you can make the database calls. Example code that would do the same as GreenDAO code would like like the one below.

        DatabaseHelper databaseHelper =
                OpenHelperManager.getHelper(this, DatabaseHelper.class);

        Dao<Task, Integer> dao = null;
        Dao<Project, Integer> pdao = null;
        try {
            pdao = databaseHelper.getProjectDao();
            dao = databaseHelper.getTaskDao();
            
            Project p = new Project();
            p.name = "project";
            pdao.create(p);
            
            Task t = new Task();
            t.name = "Task ";
            t.project = p;
            t.description = "Description";
            dao.create(t);
            
        } catch (SQLException e) {
            e.printStackTrace();
        }

OrmLite throws the SQLException when in trouble so we have to wrap our code in the try catch clause and react appropriately. The code above is pretty similiar to the one that GreenDAO uses - after all most of the ORM libraries uses the same or close syntax and approach to dealing with data access.

I will try to add some additional description over next few days.

Tags: