Realm local migration for Xamarin Forms Apps


#1

Realm documentation promises that schema changes of local Realm databases in Xamarin Forms can be updated in two methods. neither of which I have been able to get to work as expected. I have, however, found a workaround using a third, but drastic, method.
Here’s the issue: Use of either Migration Callbacks or Realm.Deletes do SEEM to work until the App is restarted. Then it becomes apparent that Realm schema data utilized only then was not properly updated earlier. If a Migration Callback was performed the error will be that the current schema version does not match the expected schema version. If a Realm.Delete was instead used, the error will be a list of all the items that nonetheless remain “unmigrated”, even though the app had seemed to work OK until the restart.
Both these results have been reported but as I cannot afford the professional support fee, nothing has improved over many moths. Perhaps someday they will.
Until then, here is my workaround:

  1. Whenever the app is put to sleep (Android or iOS) or actually ended (UWP), store something in the app’s current properties that signifies the existing schema arrangement, execute await Xamarin.Forms.Application.Current.SavePropertiesAsync(); AND backup all data into XML files in an app Backup folder. For “something” I use a static class and static string (I call it SchemaVersions.) within it that I know will be available before any non-static code is executed.
  2. Whenever you make a schema change, adjust the static SchemaVersions or its equivalent to a different value.
  3. When the app is updated on the device, provide code that executes BEFORE any Realm instances are created to verify whether the static and stored values of SchemaVersions are identical. If not, set a flag, say one called RealmUpdateRequired, and log which Realm databases are affected, if you have more than one database.(My SchemaVersions is a string of semi-colon separated name:schema value strings for my several Realm databases.)
  4. Perform all Realm GetInstance()s with the ShouldDeleteIfMigrationRequired flag set in their Configs.
  5. Afterward, check if the RealmUpdateRequired or such flag was set and restore the now missing data in the affected database(s) from the backup XML files. Inform your user what has happened.
    I also chose to use PCLCrypto to encrypt / decrypt my XML backup files; if you do the same you’ll need appropriate code for that.
    This really was a lot of work and I will be glad to share more details with anyone, via the Contact page on my web site https://www.jwcontacts.com.
    If you have suggestions for a better workaround or have been able to get Migration to work properly, please also do get in touch with your details.

#2

A bit more elaboration:
Every Realm type whose schema was updated cannot be restored directly from XML as the XML expects to be read using the type’s old schema, which no longer exists in your updated code. So I also have to check whether the XML type is equivalent to the current definition of the same-named type. If not, I create a dynamic ExpandableObject, adding into its internal dictionary the old schema’s properties. I can then read the XML document using that new dynamic object and use the resultant instance properties to set those which match in a new instance of the new type, then save that instance of the desired type. Be forewarned that reading properties that are byte arrays from an XML document require special handling as they may otherwise throw an error if read simply as strings.
The use of XML backup files does, of course, double the storage required of your app’s data. This may be a real concern if Realm handles huge amounts of data.