我使用的是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;
}
stacktrace的相关部分
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)
谢谢!
答案 0 :(得分:1)
你的逻辑实际上有些错误。通过在事务外部执行查询,后台同步线程可以在您执行查询和开始事务之间将数据放入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都处于脱机状态:
PlannerManager
。PlannerManager
。copyToRealm
相当于手动设置所有字段。使用Realm.createObject()
使用特殊的"默认"所有字段的指令,自动丢失到使用普通Java setter(以及copyToRealm
使用的)时使用的任何显式集。