Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Set Up Database Migrations With greenDAO

DZone's Guide to

How to Set Up Database Migrations With greenDAO

Setting up database migrations is easy with greenDAO. greenDAO helps you open the database and also defines what happens when your schema version changes.

· Mobile Zone
Free Resource

Download this comprehensive Mobile Testing Reference Guide to help prioritize which mobile devices and OSs to test against, brought to you in partnership with Sauce Labs.

If you’ve ever used greenDAO, you’ve probably used their DevOpenHelper class. As the name implies, it helps you open the database, but it also defines what happens when your schema version changes. If you read the documentation for this class, you will see this: WARNING: Drops all table on Upgrade! Use only during development.

So, if you ever change your schema (such as add a new table), it will drop all tables first, wiping the database. For development, where the schema is constantly changing, this might be fine. But, once your app is released, your users probably won’t be happy if all of their data gets deleted when they update.

This is where database migrations come in, and why you should not be using DevOpenHelper in production. Instead of deleting all of your data, you can tell greenDAO how to handle schema version changes. That way your data does not get lost, and app updates are seamless.

Setting Up Migrations

To demonstrate this, I took the example app from greenDAO’s GitHub and modified it to include migrations. You can find my example project here. Below is the final version of the class used to perform the migrations.

public class DatabaseUpgradeHelper extends DaoMaster.OpenHelper {

    public DatabaseUpgradeHelper(Context context, String name) {
        super(context, name);
    }

    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        List<Migration> migrations = getMigrations();

        // Only run migrations past the old version
        for (Migration migration : migrations) {
            if (oldVersion < migration.getVersion()) {
                migration.runMigration(db);
            }
        }
    }

    private List<Migration> getMigrations() {
        List<Migration> migrations = new ArrayList<>();
        migrations.add(new MigrationV2());
        migrations.add(new MigrationV3());

        // Sorting just to be safe, in case other people add migrations in the wrong order.
        Comparator<Migration> migrationComparator = new Comparator<Migration>() {
            @Override
            public int compare(Migration m1, Migration m2) {
                return m1.getVersion().compareTo(m2.getVersion());
            }
        };
        Collections.sort(migrations, migrationComparator);

        return migrations;
    }

    private static class MigrationV2 implements Migration {

        @Override
        public Integer getVersion() {
            return 2;
        }

        @Override
        public void runMigration(Database db) {
            //Adding new table
            UserDao.createTable(db, false);

        }
    }

    private static class MigrationV3 implements Migration {

        @Override
        public Integer getVersion() {
            return 3;
        }

        @Override
        public void runMigration(Database db) {
            // Add new column to user table
            db.execSQL("ALTER TABLE " + UserDao.TABLENAME + " ADD COLUMN " + UserDao.Properties.Age.columnName + " INTEGER");
        }
    }

    private interface Migration {
        Integer getVersion();

        void runMigration(Database db);
    }
}

If you want to try it out, you can clone my example project, and check out the commit 689fa205d87e5c74f27e25588eb1b2a5f41588be. This will take you to the first schema version. At this point, there is only a Note table. If you try running the app, you can add some notes to the database.

Now, if you check out the next commit 23fd3802fd105873584023c807b60120b93da142 it will take you to the second schema version. In this version I added a User table. If you were using the DevOpenHelper class, running the app here would delete the notes you had made previously. Since we are doing a migration, that won’t happen. If you run the app, you can try adding a User, and you will see that your notes are still there.

Lastly, if you check out the third schema version 5c1367164620858c814cf87860771c06c8140f77 and install the app, it will run another migration. In this version, I added an age to the User. If you run the app, again none of the data gets lost, and you can now set the age of a User.

In this example, we could have also jumped straight from schema version 1 to 3, and the migrations would still work. It would have run two migrations instead of one. It doesn’t matter what version the user is updating from, the migrations will still work.

Final Thoughts

You only need migrations when you’re releasing a new version of the app, and you made changes to the database. If you’re in development and constantly making changes to the database, you don’t need to keep updating the schema version, though you should be aware that during development, if you add a new table for example and update the app on a device that already had it installed, it won’t update the database because the schema version hasn’t changed, which will cause the app to crash if you try to query the database for that table (since it doesn’t exist yet).

Sometimes during development, it’s best to just keep using DevOpenHelper and updating the schema version. Just remember to change it back for release. Alternatively, if you update the database schema, you can clear the data for your app. That way it will force it to recreate the database with the altered schema.

Analysts agree that a mix of emulators/simulators and real devices are necessary to optimize your mobile app testing - learn more in this white paper, brought to you in partnership with Sauce Labs.

Topics:
database ,tutorial ,migrations ,greendao ,android

Published at DZone with permission of Pierce Zaifman, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}