What do you want to achieve?
Copy a pre-filled database from assets by using .assetFile(context, "default.realm")Expected Results
Database gets copied and contains all the data
Actual Results
Copied database is only 4kb in size, while the original database in the assets folder is 123kb in size.
Using realm.isEmpty() returns true, which it should not. The Realm Browser for OS X correctly shows all the data in the database. Using realm.where() always returns an empty result.Steps & Code to Reproduce
RealmConfiguration config = new RealmConfiguration.Builder(context)
.name("default.realm")
.schemaVersion(1)
.assetFile(context, "default.realm")
.deleteRealmIfMigrationNeeded()
.build();Realm realm = Realm.getInstance(config);
realm.isEmpty() // => true
Using this code, realm.isEmpty() always prints true
Realm version(s): 1.0.0
Android Studio version: 2.2 Preview 2
Which Android version and device: CM 13 Android 6.0.1 Galaxy S5 klte
Hi @AlexLardschneider
The file will only be copied if one isn't already present. Is there a chance that might be the case?
E.g. during development, files will not be deleted unless you uninstall the app.
Hi @cmelchior thanks for the quick response.
Clearing app data or even uninstalling did not solve the issue unfortunately. Also made sure that no database with the same name was already present, which wasn't the case.
Hmm, strange. Can you provide a sample project where this fails?
The 4kb is the size of our buffer when copying the file, so it sounds like something is going wrong when it is being copied, but in that case an exception should be thrown. Can you check the log if something seems wrong there?
If that is not the case. Can you provide a sample project with this bug?
Scanning the logcat for any errors or messages about realm does not yield and results, nor can I find any exceptions indicating there is something wrong with realm. Will provide a sample project ASAP.
So for some reason restarting Android Studio and doing a full project clean & rebuild fixed the issue, as the database is getting copied correctly now and contains all the data. Kinda seems strange to me, but I'll see if I can reproduce this issue and report back.
As the problem still exists I send a sample project to [email protected].
Thanks, I am looking into it.
Hi @AlexLardschneider
I found the problem. The Realm Version is 1 in the file you copied and set to 5 in your configuration. This causes a RealmMigrationNeededException to be thrown, but because you set deleteRealmIfMigrationNeeded the file is just deleted and an empty Realm created instead.
This looks like a bug on our part since you are allowed to set a non-zero version number on an empty Realm and copying a existing Realm file is more or less the same thing.
Only one of deleteRealmIfMigrationNeeded and assetFile can be used at the same time IMO.
I tend to agree. The interaction between the two is odd at best. So
1) Throw if setting assetFile and deleteRealmIfMigrationNeeded is set at the same time
2) Allow to set another version number on the asset file, just like for an empty Realm, i.e. no migration needed for it.
What do you think?
Allow to set another version number on the asset file.
Wouldn't setting to the right version in the asset file the most expected behaviour? I'd like to have a fixed preset version in the asset file if it can be achieved by the user through existing tools (does Realm Browser support that?).
I think there could be made arguments for both cases, but I agree that requiring the same version is safer as it forces you to think harder about schema compatibility. So I think I would be fine with keeping that requirement, although we should probably look into providing a better exception message in that case, right now it get hidden by a "RealmMigration missing" exception.
We should also add some more documentation to assetFile/deleteRealmIfMigrationNeeded to make these corner cases more clear.
Thanks for getting back to me.
So if I understood correctly, removing deleteRealmIfMigrationNeeded and setting the schema version to 0 should fix the issue, right?
So lets say I supply a database which gets copied on first app start, and the version is set to 0. If I make changes to the database in the assets file and set the version to 1, the old database should get deleted and replaced by the new one located in the assets. Or is there an other way to archieve this?
It looks like the version of the Realm file is 1, so just setting your app schema version to 1 should fix the problem you are seeing.
Having deleteRealmIfMigrationNeeded() will hide any bugs in the asset file you are copying though, so I would recommend removing that also.
So how should upgrading databases from the asset files be handled?
Btw, where can you see/edit the current database version?
assetFile is not meant for upgrading existing databases, but for providing an initial dataset.
If you want to replace an existing Realm file with the one from assets, you can call Realm.deleteRealm(realmConfig) before calling getInstance() for the first time. That will remove any existing database. In most cases you probably want to add a migration instead.
You can get the version of realm by calling realm.getVersion(). Setting the Realm version can only be done through RealmConfiguration.Builder.version()
So I should first of all check the version of the old database, check if it needs upgrading, if yes delete it, and then call getInstance() to copy it from assets? Or is there a better way to do it? Also wouldn't realm.getVersion() return the version you set in RealmConfiguration.Builder.version()? If yes, from where can I get the version of the current db?
@cmelchior realm.getVersion() requires a opened a realm instance first. In @AlexLardschneider 's case, he needs to use DynamicRealm.getVersion() which won't throw MigrationNeedException first.
Try:
DynamicRealm dynamicRealm = DynamicRealm.getInstance(config);
long version = dynamicRealm.getVersion();
@AlexLardschneider I think you are misunderstanding the purpose of assetFile. It should not be used when upgrading an existing app. For that you should write a migration instead.
But if you really want to know the version, what @beeender describes is the way to do it.
Just to make sure this information is clear from https://github.com/realm/realm-java/issues/2933#issuecomment-223881611. This issue is now about this:
1) Throw if setting assetFile and deleteRealmIfMigrationNeeded is set at the same time
2) If the schema version in the assetFile is different than the configured one. An IllegalArgumentException should be thrown saying that.
Reading through the PR make me think a little:
Imagine in v1 you set
.assetFile("myV1data")
.schemaVersion(1)
.migration(new MyMigration)
Then something prompt an schema upgrade version
.assetFile("myV1data")
.schemaVersion(2)
.migration(new MyMigration)
The impact for new installs would that they copy myV1Data, try to open that file, which then throw a MigrationNeededException that triggers the migration. Which is fine right?
Because with my item 2) above, that would no longer work. So Perhaps we shouldn't implement 2) after all?
Because with my item 2) above, that would no longer work. So Perhaps we shouldn't implement 2) after all?
Uh, I just finished implementing it and realized in a unit test that we don't need the 2nd case as it blocks proper migration case. So I was about to say that. 馃槄 I too think 2nd case isn't necessary.
@beeender Could you add some thought?
I think we shouldn't implement 2) .
The assetFile() will only do a copy if the file doesn't exist, and that's all. The following operations are just the same as others. (and 1) is still needed.) Otherwise the complexity is beyond my brain capacity.
@AlexLardschneider
The issue is covered now, and you'd get an except with a detailed message in the next release. Thanks for reporting the issue to us! I'm closing the issue for now.
Most helpful comment
I think there could be made arguments for both cases, but I agree that requiring the same version is safer as it forces you to think harder about schema compatibility. So I think I would be fine with keeping that requirement, although we should probably look into providing a better exception message in that case, right now it get hidden by a "RealmMigration missing" exception.
We should also add some more documentation to
assetFile/deleteRealmIfMigrationNeededto make these corner cases more clear.