Realm 找不到现有项目



我正在使用 Realm 3.4.0 并且有一个对象应该是单例。数据库已同步。

下面是代码的简化版本:测试该对象是否存在,如果不存在,则添加它。正确的方法是什么?(copyToRealmOrUpdate 不应该是必需的,或者是否有任何其他原因导致实例变为空?

@PrimaryKey
public long id = 1;
public static PlannerManager getInstance(Realm realm) {
PlannerManager ourInstance = null;
if (instanceLock == null)
instanceLock = new ReentrantLock();
try {
instanceLock.lock();
realm.refresh(); // Force getting all data from online database
ourInstance = realm.where(PlannerManager.class).findFirst();
if (ourInstance == null) { // The item doesn't exist
realm.beginTransaction();
ourInstance = realm.copyToRealm(new PlannerManager()); // Crashes sometimes with the error that an object with primary ID already exists
realm.commitTransaction();
}
} finally {
instanceLock.unlock();
}
return ourInstance;
}

堆栈跟踪的相关部分

2:9.446 Primary key value already exists: 1 .
(/Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_OsObject.cpp:189) io.realm.exceptions.RealmPrimaryKeyConstraintException: Primary key value already exists: 1 .
(/Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_OsObject.cpp:189)
at io.realm.internal.OsObject.nativeCreateNewObjectWithLongPrimaryKey(Native Method)
at io.realm.internal.OsObject.createWithPrimaryKey(OsObject.java:198)
at io.realm.Realm.createObjectInternal(Realm.java:1052)
at io.realm.PlannerManagerRealmProxy.copy(PlannerManagerRealmProxy.java:1279)
at io.realm.PlannerManagerRealmProxy.copyOrUpdate(PlannerManagerRealmProxy.java:1268)
at io.realm.DefaultRealmModuleMediator.copyOrUpdate(DefaultRealmModuleMediator.java:438)
at io.realm.Realm.copyOrUpdate(Realm.java:1660)
at io.realm.Realm.copyToRealm(Realm.java:1072)
at com.myapp.internal.PlannerManager.getInstance(PlannerManager.java:857)

谢谢!

你的逻辑实际上有点错误。通过在事务之外执行查询,后台同步线程可能会在你执行查询和开始事务之间将数据放入 Realm 中。事务总是会将 Realm 数据库移动到最新版本,因此也不需要调用refresh()。你的逻辑应该是这样的:

realm.beginTransaction();
ourInstance = realm.where(PlannerManager.class).findFirst();
if (ourInstance == null) {
ourInstance = realm.createObject(PlannerManager.class, 1);
realm.commitTransaction();
} else {
realm.cancelTransaction();
}

请注意,使用realm.copyToRealm()将导致覆盖来自其他设备的更改,因此对于此类初始数据,使用createObject更安全,因为对各个字段的更改将正确合并。使用copyToRealm()与实际将所有字段设置为初始值相同。

例如,如果您有两个设备A和B都处于离线状态:

  1. 启动应用并创建默认PlannerManager
  2. A 修改PlannerManager中的字段。
  3. B 启动应用程序,但由于 A 处于脱机状态,因此它不知道 PlannerManager 已创建,因此它还会创建默认的 PlannerManager。
  4. A 和 B 都上线。
  5. 由于 Realm 使用"最后写入优先"的方式,B 现在将覆盖 A 所做的所有更改,因为使用copyToRealm相当于手动设置所有字段。

使用Realm.createObject()对所有字段使用特殊的"默认"指令,该指令会自动丢失到任何显式集合中,例如使用普通 Java setter(以及copyToRealm使用(时使用的显式集合。

最新更新