Is it any chance to expose MigrationCallback to be used by developers? Example as a part of RealmConfiguration API:
RealmConfiguration config = new RealmConfiguration.Builder()
.schemaVersion(2)
.migration(new MyMigration(), new MyMigrationCallback() )
.build()
In my scenario I need to be notified once migration is completed. I have custom logic defined in my model classes, and I am not able to run it using DynamicRealm during migration as it operates on Realm (not dynamic one).
And btw is it MigrationCallback internally used at all? I didnt find any valid occurrence.
Interesting. Can you elaborate on what kind of logic?
I am calculating hash code of realm objects and store it as a field, so that I can check if object was modified or not.
After making changes in schema i added additional field and now had to take it into account during hash calculation. What that means is after the migration i have to update hash codes of all objects which schema was changed.
When objects are complex (contatins list of other objects which contains list of other objects...) such hash calculation may be hard using dynamic realm. It woud be much easier to just use method calculateHash() provided by my models themself.
Thanks .... my initial gut reaction would be that exposing such a callback would have very limited applicability and thus something we would be hesitant to do. Something that seems a lot more useful could be Realm.isMigrationRequired(config). Having such a standalone check could also be used for other things, like showing an "Upgrade" screen while doing the migration, although e.g. https://github.com/realm/realm-java/issues/2299#issuecomment-185572794 was created to discuss this.
This would enable the following pattern: Thoughts @realm/java and @roughboy?
if (Realm.isMigrationRequired(config)) {
Realm.migrateRealm(config);
// Run custom migration on the Realm
}
Yes, it would definitely do the job. However, some additional info should be also available - i mean schema number of the realm file that is going to be migrated.
From the other side having callback defined as :
interface MigrationCallback {
void migrationComplete(int fromSchemaNumber, int toSchemaNumber);
}
would also be elegant.
Why do you need the schema version of the file being migrated? You know it will be the latest when it is done with the migration? It is possible today to get the schema pre-migration version using
DynamicRealm dynRealm = DynamicRealm.getInstance(config);
long version = dynRealm.getVersion();
dynRealm.close();
EDIT: That isn't to say that https://github.com/realm/realm-java/issues/4083#issuecomment-274060514 isn't more elegant and will solve your problem spot on. But we also have to be mindful of the API not trying to support every use case directly, since a bigger API surface impacts everyone.
You are totaly right - after migration it will be latest version. Pre-migration number should be useful when applying version specific changes. So summing up, this would look like below:
DynamicRealm dynRealm = DynamicRealm.getInstance(config);
long version = dynRealm.getVersion();
dynRealm.close();
if (Realm.isMigrationRequired(config)) {
Realm.migrateRealm(config);
if (version == X) {
// Run custom migration on the Realm
version++;
} else if (version == X+1) {
// Run custom migration on the Realm
version++
}
}
Yes, if your custom migration required knowledge about what state it started from.
Is it not possible to just use transform() as part of the migration?
And you can use this pattern with Realm too which allows you to handle each version in your migration
But exposing the callback makes sense if you want to move the migration to a background thread.
@Zhuinden
It is possible, i'm not saying its' not. However it will be more complex, more error-prone, and will duplicate logic stitched in realm model.
It is much harder to operate on objects using DynamicRealm. You have to pay a lot attention on fields names and types.
It seems expose the schema version getter API would be another solution? I am always wanting a getter API for the schema version ...
We already expose the version number throught realm.getVersion() or dynamicRealm.getVersion(), or do you think of something else?
AH!! i forgot! But that requires you open the Realm first. If we have a static method like Realm.getVersion(RealmConfigurartion config);
then this can be simply achieved by current APIs like:
RealmConfiguration config = new RealmConfiguration.Builder()
.schemaVersion(2)
.migration(new MyMigration(), new MyMigrationCallback() )
.build()
long oldVersion = Realm.getVersion(config);
Realm.getInstance(config);
if (oldVersion < 2) {
// Migration happened and finished successfully. Just do the thing you want to do in the MyMigrationCallback
}
@beeender I remember a trick that you could do
long schemaVersion = 0;
DynamicRealm dynRealm = DynamicRealm.getInstance(config);
schemaVersion = dynRealm.getVersion();
dynRealm.close();
That way you don't trigger a RealmMigrationNeededException to obtain the schemaVersion
Yes! by opening a DynamicRealm instance could do that!
That method would just use the dynamic API behind the scenes, but I agree that not many will realise that going through the dynamic API is possible, so adding Realm.getVersion(config) will probably make it easier for users.
Thinking about it a bit more, it seems to me that just having the current schema version should be enough to predict if a migration is required.
The use cases so far seems to be:
1) Be able to detect when a migration is required in order to display a "Upgrading DB" splash screen
2) Be able to detect what version we are upgrading from in order to apply custom logic.
// A. Works with current API
RealmConfiguration config = new RealmConfiguration.Builder().schemaVersion(2).build();
long schemaVersion = 0;
DynamicRealm dynRealm = DynamicRealm.getInstance(config);
schemaVersion = dynRealm.getVersion();
dynRealm.close();
// Custom migration logic
if (schemaVersion < config.getSchemaVersion()) {
Realm.migrateRealm(config);
if (schemaVersion == 1) {
doSchemaVersion1Migration();
schemaVersion++;
}
if (schemaVersion == 2) {
doSchemaVersion2Migration();
schemaVersion++;
}
}
// Splash screen
if (schemaVersion < config.getSchemaVersion()) {
showSplashScreen();
Realm.migrateRealm(config);
hideSplashScreen();
}
We could add a Realm.getSchemaVersion(config) for the readability perhaps, but maybe just documenting it in the docs would be enough for now?
It maybe confusing when considering following scenario:
RealmConfiguration config = new RealmConfiguration.Builder()
.name("myrealm.realm")
.schemaVersion(3)
.modules(new MySchemaModule())
.migration(new MyMigration())
.build();
Realm.getSchemaVersion(config) // returns 2
Maybe something like Realm.getCurrentSchemaVersion(config) instead ??
@roughboy such a long name... but a valid concern.
I do think it would be useful to have the MigrationCallback because you might want to run the migration on a background thread.
A callback wouldn't solve that? In that case you would need something like getInstanceAsync(): https://github.com/realm/realm-java/issues/2299
I'm folding this issue into #4669 since this issue is a subset of that.
The use case described in https://github.com/realm/realm-java/issues/4083#issuecomment-275646298 is now covered by getInstanceAsync()
Most helpful comment
Thanks .... my initial gut reaction would be that exposing such a callback would have very limited applicability and thus something we would be hesitant to do. Something that seems a lot more useful could be
Realm.isMigrationRequired(config). Having such a standalone check could also be used for other things, like showing an "Upgrade" screen while doing the migration, although e.g. https://github.com/realm/realm-java/issues/2299#issuecomment-185572794 was created to discuss this.This would enable the following pattern: Thoughts @realm/java and @roughboy?