9

So we have a scenario where a user has version 1.0 of an app. Version 2.0 comes out, but the user does not update. When version 3.0 comes out, the user decides to update.

Because the user has not updated the app, the realm file has not been updated either, so while doing migration from version 1.0 to version 3.0 the version parameter of Migration.execute will have the value 1 instead of 2.

There are also issues when the user installs directly version 2.0 of the app and then migrates to version 3.0. The same as in the previous case, the version parameter will be wrong.

Is there a way to properly handle these cases?

gookman
  • 2,527
  • 2
  • 20
  • 28

3 Answers3

4

Actually Realm's migration example shows this scenario.

public class Migration implements RealmMigration {
    @Override
    public long execute(Realm realm, long version) {
        // Step 0
        if (version == 0) {
        //Do the migration from 0 to 1
            version++;
        }

        // Step 1
        // Now the version is at least 1
        if (version == 1) {
        // Do the migration from 1 to 2
           version++;
        }

        // Step 2
        if (version == 2) {
        // Do the migration from 2 to 3
           version++;
        }
        // Now you get your final version 3
        return version;
    }
}

Simply just write the migration step by step, run them one by one until you get the latest schema version. For in your case, the user might have a Realm db version 0 here, and the step0 will run first. Then the version bump to 1 in the step 0 block, and the step 1 will run then.

------------ Update for user install version 3 directly case ------------

When create the realm instance, the code would be like:

RealmConfiguration config = new RealmConfiguration.Builder(this)
                             .migration(migration)
                             .schemaVersion(3)
                             .build();
Realm realm = Realm.getInstance(config);

Please notice that the schemaVersion(3) here. The RealmMigration.execute() will only be executed if a migration is needed. This means if user install version 3 directly without having any previous version installed on the device, the RealmMigration.execute() won't be called and the after the Realm file initialized, the schema version will be set to 3.

beeender
  • 3,555
  • 19
  • 32
1

I'm not the Realm guru and I haven't used Realm in the real projects, but this approach should work:

Let's assume that you use this migration example:

You need an additional property saved in the project (in SharedPreferences for instance) - latestMigrationVersion. By default, latestMigrationVersion = 0, which means we didn't run migrations yet.

Modify you Migration.java class in the following way:

@Override
public long execute(Realm realm, long version) {

    // check if the previous migration took place
    if (version > 0 && version - 1 > latestMigrationVersion) {
        // user missed migration
        // then we need to run previous missed migrations before
        version = latestMigrationVersion;
    }

    // do migrations as described in the example.
    ...

    // update latestMigrationVersion for future checks
    latestMigrationVersion = version;
    // save the property locally
}

Now, if the user directly installs the 2.0 version, all previous migrations will be executed, before 2.0 -> 3.0 migration.

Unit tests should help you to check all possible migrations: 0.0 -> 3.0, 1.0 -> 2.0, 2.0 -> 3.0, etc.

Veaceslav Gaidarji
  • 4,261
  • 3
  • 38
  • 61
0

Like beeender said, migrations in Realm are changed quite a bit, the key points on making a realm (0.84.2) migration work for me were understanding that:

  • The schemaVersion is always 0 when your app has a realm db without specifying the schemaVersion. Which is true in most cases since you probably start using the schemaVersion in the configuration once you need migrations & are already running a live release of your app.

  • The schemaVersion is automatically stored and when a fresh install of your app occurs and you are already on schemaVersion 3, realm automatically checks if there are exceptions, if not it sets the schemaVersion to 3 so your migrations aren't run when not needed. This also meens you don't have to store anything anymore in SharedPreferences.

  • In the migration you have to set all values of new columns when the type is not nullable, ...

  • Empty Strings can be inserted but only when setting convertColumnToNullable on the column

Jordy
  • 1,764
  • 1
  • 22
  • 32