领域和自动增量行为(Android)

我试图从一个ID作为参考从领域获取数据。 但是,在查询ID时,我发现Realm为所有元素(ID为0)提供了相同的ID。 为什么当我在模型ID上使用@PrimaryKey注解时ID不自动递增?

以下是该模型的缩短课程:

 public class Child_pages extends RealmObject { @PrimaryKey private int id_cp; private int id; private String day; private int category_id; 

而我正在执行的查询是: realm.where(Child_pages.class).equalTo("id_cp",page_id).findFirst()

领域目前不支持自动递增主键。 但是你可以使用类似的东西来轻松地实现它:

 public int getNextKey() { try { Number number = realm.where(object).max("id"); if (number != null) { return number.intValue() + 1; } else { return 0; } } catch (ArrayIndexOutOfBoundsException e) { return 0; } } 

我希望能让你开始。

Java绑定尚不支持主键,但它在路线图上并具有高优先级 – 请参阅: https : //groups.google.com/forum/# ! topic/ realm-java/ 6hFqdyoH67w 。 作为一种解决方法,您可以使用这段代码来生成密钥:

 int key; try { key = realm.where(Child_pages.class).max("id").intValue() + 1; } catch(ArrayIndexOutOfBoundsException ex) { key = 0; } 

我使用单一工厂生成主键作为更通用的解决方案,具有更好的性能(每次感谢AtomicInteger都不需要查询max("id") )。

在Realm Git Hub中有一个很长的讨论,如果你需要更多的上下文: 记录如何设置自动递增ID?

如前所述,自动递增还不被支持。

但是对于那些使用kotlin的人,并希望有一个自动递增行为的领域,这是可能性之一:

 open class Route( @PrimaryKey open var id: Long? = null, open var total: Double? = null, open var durationText: String? = null, open var durationMinutes: Double? = null, open var distanceText: String? = null, open var distanceMeters: Int? = null): RealmObject() { companion object { @Ignore var cachedNextId:Long? = null get() { val nextId = if (field!=null) field?.plus(1) else Realm.getDefaultInstance()?.where(Route::class.java)?.max("id")?.toLong()?.plus(1) ?: 1 Route.cachedNextId = nextId return nextId } }} 

如果你的ID很长,那么:

 val nextId = bgRealm.where(Branch::class.java).max("localId") as Long + 1 

可悲的是,我不能评论其他答案,但我想补充Vinicius`答案 。

首先,在查找主键时,特别是在不关闭它们时,不应该打开一个新的领域实例,因为这会增加最大可能的文件描述符计数。

其次,虽然这是一个优先选择,但不应该有原始类型(或对象等价物)作为可空( Kotlin ),因为这会增加冗余要求来检查可空性。

第三,由于您使用的是kotlin,因此您可以为Realm类定义一个扩展方法,例如:

 fun Realm.getNextId(model: RealmModel, idField : String) : Long { val count = realm.where(model::class.java).max(idField) return count + 1L } 

由于所有的RealmObject实例都是RealmModel ,甚至没有被Realm跟踪的对象仍然是RealmModel实例,因此在您使用领域相关类的任何地方都可以使用它们。 Java相当于:

 static long getNextId(RealmModel object, Realm realm, String idField) { long count = realm.where(object.class).max(idField); return count + 1; } 

延迟编辑注意事项:如果您处理可能来自外部来源的数据(如其他数据库或Web),则最好不要使用此方法,因为这会导致内部数据库中的数据发生冲突。 相反,你应该使用max([id field name]) 。 看到以前的片段,我已经修改它们以适应这个编辑。

//编辑

我发现这个新的解决方案在这个问题上

 @PrimaryKey private Integer _id = RealmAutoIncrement.getInstance().getNextIdFromDomain(AccountType.class); 

//原始答案

我只是想分享我的解决这个问题的尝试,因为我不想一直传递一个主键值。 首先我创建了一个数据库类来处理RealmObject的存储。

 public class RealmDatabase { Realm realm; public RealmDatabase() { RealmConfiguration realmConfiguration = new RealmConfiguration.Builder() .name("test").schemaVersion(1).build(); try { realm = Realm.getInstance(realmConfiguration); } catch (Exception e) { Log.e("Realm init failed", e.getMessage()); } } protected void saveObjectIntoDatabase(final RealmObject object) { realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm bgRealm) { bgRealm.copyToRealm(object); } }, new Realm.Transaction.OnSuccess() { @Override public void onSuccess() { // onSuccess } }, new Realm.Transaction.OnError() { @Override public void onError(Throwable error) { // onError } }); } 

在创建数据库类后,我创建了一个接口来区分具有主键和无主键的对象。

 public interface AutoIncrementable { public void setPrimaryKey(int primaryKey); public int getNextPrimaryKey(Realm realm); } 

现在你只需要编辑上一个执行方法的代码

 if(object instanceof AutoIncrementable){ AutoIncrementable autoIncrementable = (AutoIncrementable) object; autoIncrementable.setPrimaryKey(autoIncrementable.getNextPrimaryKey(bgRealm)); bgRealm.copyToRealm((RealmObject)autoIncrementable); } else { bgRealm.copyToRealm(object); } 

有了这个解决方案,数据库逻辑仍然在一个类中,这个类可以传递给每个需要写入数据库的类。

 public class Person extends RealmObject implements AutoIncrementable{ @PrimaryKey public int id; public String name; @Override public void setPrimaryKey(int primaryKey) { this.id = primaryKey; } @Override public int getNextPrimaryKey(Realm realm) { return realm.where(Person.class).max("id").intValue() + 1; } } 

有关进一步的建议,请随时留下评论。