realm-java
realm-java copied to clipboard
Realm.deleteAll() is trying to delete RealmObjects across module boundaries
I have a project with multiple modules using Realm. I was hoping that I could just call deleteAll()
on a Realm
for one of the modules, but it seems to be trying to delete RealmObjects
from the other modules, leading to a runtime exception.
Expected Results
I'd expect
deleteAll()
to only delete theRealmObject
s within the associatedRealm
.
Actual Results
When the code runs, I get the following runtime exception when calling
deleteAll()
on the libraryRealm
instance:
Caused by: io.realm.exceptions.RealmException: 'AppModel' doesn't exist in current schema.
at io.realm.internal.ColumnIndices.getColumnInfo(ColumnIndices.java:112)
at io.realm.RealmSchema.getColumnInfo(RealmSchema.java:250)
at io.realm.ImmutableRealmSchema.get(ImmutableRealmSchema.java:41)
at io.realm.RealmSchema.getAll(RealmSchema.java:88)
at io.realm.BaseRealm.deleteAll(BaseRealm.java:602)
at io.realm.Realm.deleteAll(Realm.java:135)
at com.johnpetitto.realmbug.MainActivity.lambda$onCreate$1$MainActivity(MainActivity.java:30)
at com.johnpetitto.realmbug.MainActivity$$Lambda$1.execute(Unknown Source:0)
at io.realm.Realm.executeTransaction(Realm.java:1394)
at com.johnpetitto.realmbug.MainActivity.onCreate(MainActivity.java:30)
at android.app.Activity.performCreate(Activity.java:6998)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1230)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2899)
Steps & Code to Reproduce
I created a sample project to reproduce this. Basically there is an app module and a library module. The library module has a
@RealmModule
in order to differentiate itself from the app code. Both modules contain a singleRealmObject
. Here is a repository with the full code.
Code Sample
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Realm.init(this);
try (Realm realm = Realm.getDefaultInstance()) {
realm.executeTransaction(r -> r.deleteAll());
}
RealmConfiguration libraryConfig = new RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.modules(new LibraryModule())
.build();
try (Realm realm = Realm.getInstance(libraryConfig)) {
realm.executeTransaction(r -> r.deleteAll());
}
}
Version of Realm and tooling
Realm version(s): 4.3.3
Realm sync feature enabled: no
Android Studio version: 3.0
Which Android version and device: Android 8 on a OnePlus 3T
I would think that currently, Realm.deleteAll()
tries to delete the items for all currently existing classes that are in the schema of the existing Realm file.
I'm actually more surprised that
try (Realm realm = Realm.getInstance(libraryConfig)) {
I would have expected this to have a schema mismatch and delete the Realm because migration was needed, after which it SHOULD allow deleting items. So there could be a bug there with schema caching
Hi @jpetitto Thanks for the nice example project. I'm able to reproduce the behaviour and something indeed looks fishy. I'm looking into it.
I found the issue(s).
-
You are re-using the underlying file between the two Realm instances. This means that when you open the library instance, the class "AppModel" is already in there. Currently, we don't treat extra tables as an error as long as they don't conflict with the schema you define.
-
The problem arises when you call
schema.getAll()
(whichdeleteAll()
does). This method dynamically tries to load the schema information, but it will ask the Java module for information about all classes it finds including "AppModule", but that doesn't exist since it isn't part of the module, so the method crashes with the exception you see. This kinda conflicts with 1.
I suspect this error can also show up in other ways, e.g. through the Realm.isEmpty()
method which will return the wrong result.
I'll need to dig a little further, but it looks like we need to fix schema.findAll()
method to only return the classes in the defined schema for typed Realms and everything when using DynamicRealm
.
3 workarounds exist right now:
// Manually delete objects of a given type. You need to call this for all types in your module.
realm.delete(LibraryModule.class);
// Use different names for files used by app / libraries
RealmConfiguration libConfig = new RealmConfiguration.Builder()
.name("library.realm")
.build()
RealmConfiguration appConfig = new RealmConfiguration.Builder()
.name("app.realm")
.build()
// Use DynamicRealm to delete everything
DynamicRealm dynamicRealm = DynamicRealm.getInstance(config);
dynamicRealm.executeTransaction(r -> r.deleteAll());
Oh hey, it'd work with DynamicRealm? that's pretty cool, I didn't think of that.
Thanks for investigating this @cmelchior - I like the solution of using separate files for each module. I'm currently manually deleting each model type, which can be a bit error prone if I forget to update it. Glad I could help surface the issue with schema.findAll()
and using multiple modules.
Would this issue be related to what I am seeing here? - https://stackoverflow.com/questions/49164180/need-help-understanding-how-to-remove-realm-models-from-schema?noredirect=1#comment85351896_49164180