Realm 找不到现有项目
Realm doesn't find existing items
我正在使用 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:
- A 启动应用程序并创建默认
PlannerManager
。
- A 修改了
PlannerManager
中的字段。
- B 启动了应用程序,但由于 A 处于离线状态,它不知道 PlannerManager 已经创建,所以它也创建了默认的 PlannerManager。
- A和B都上线了
- 由于 Realm 使用 "last-write-wins" 的方式,B 现在将覆盖 A 所做的所有更改,因为使用
copyToRealm
等同于手动设置所有字段。
使用 Realm.createObject()
对所有字段使用特殊的 "default" 指令,自动丢失任何显式集,就像使用普通 Java setter 时使用的那样(以及 copyToRealm
使用)。
我正在使用 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:
- A 启动应用程序并创建默认
PlannerManager
。 - A 修改了
PlannerManager
中的字段。 - B 启动了应用程序,但由于 A 处于离线状态,它不知道 PlannerManager 已经创建,所以它也创建了默认的 PlannerManager。
- A和B都上线了
- 由于 Realm 使用 "last-write-wins" 的方式,B 现在将覆盖 A 所做的所有更改,因为使用
copyToRealm
等同于手动设置所有字段。
使用 Realm.createObject()
对所有字段使用特殊的 "default" 指令,自动丢失任何显式集,就像使用普通 Java setter 时使用的那样(以及 copyToRealm
使用)。