Java 领域和自动增量行为(Android)
我正在尝试使用ID作为引用从领域获取数据。但是,在查询ID时,我发现Realm为所有元素提供了相同的ID(ID为0)。为什么在模型ID上使用Java 领域和自动增量行为(Android),java,android,realm,Java,Android,Realm,我正在尝试使用ID作为引用从领域获取数据。但是,在查询ID时,我发现Realm为所有元素提供了相同的ID(ID为0)。为什么在模型ID上使用@PrimaryKey注释时,ID不会自动递增 以下是该模型的简化类: public class Child_pages extends RealmObject { @PrimaryKey private int id_cp; private int id; private String day; private i
@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\u pages.class).equalTo(“id\u cp”,page\u id).findFirst()
realm当前不支持自动递增主键。但是,您可以通过以下方式轻松实现:
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绑定尚不支持主键,但它已在路线图上,具有高优先级-请参阅: . 作为一种解决方法,您可以使用以下代码生成关键点:
int key;
try {
key = realm.where(Child_pages.class).max("id").intValue() + 1;
} catch(ArrayIndexOutOfBoundsException ex) {
key = 0;
}
我使用的是一种性能更好的更通用的解决方案(由于AtomicInteger
,每次都不需要查询max(“id”)
)
如果您需要更多的上下文,在Realm Git Hub中有一个很长的讨论://编辑 我找到了解决这个问题的新方法
@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);
}
现在您只需要编辑上一个execute方法的代码
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;
}
}
如需进一步建议,请在下面留下评论。如果您的Id很长,则:
val nextId = bgRealm.where(Branch::class.java).max("localId") as Long + 1
如前所述,还不支持自动增量 但对于那些使用kotlin并希望在realm中具有自动递增行为的人来说,这是一种可能性:
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
}
}}
遗憾的是,我不能对其他答案发表评论,但我想补充一点 首先,在查找主键时,不应打开新的领域实例,尤其是在不关闭它们时,因为这会增加最大可能的文件描述符计数 第二,尽管这是一个首选项,但不应该将基元类型(或对象等价物)作为可空值(在Kotlin中),因为这增加了检查可空性的冗余要求 第三,因为您使用的是kotlin,所以您可以定义一个扩展方法到
Realm
类,例如:
fun Realm.getNextId(model: RealmModel, idField : String) : Long
{
val count = realm.where(model::class.java).max(idField)
return count + 1L
}
由于所有的RealmObject
实例都是realmodel
,即使没有被领域跟踪的对象也仍然是realmodel
实例,因此无论您在哪里使用领域相关类,它都是可用的。Java等价物是:
static long getNextId(RealmModel object, Realm realm, String idField)
{
long count = realm.where(object.class).max(idField);
return count + 1;
}
后期编辑注意:如果您处理的数据可能来自外部源(如其他数据库或web),最好不要使用这种方法,因为这将导致内部数据库中的数据之间发生冲突。相反,您应该使用
max([id字段名])
。请参阅前面的代码段,我已经对它们进行了修改以适应此编辑。这是一个通用解决方案,personnaly我创建了一个名为RealmUtils的类,并添加了此类方法:
public static int getPrimaryKey(Class c)
{
Realm realm = Realm.getDefaultInstance();
String primaryKeyFied = realm.getSchema().get(c.getSimpleName()).getPrimaryKey();
if (realm.where(c).max(primaryKeyFied)== null)
return 1;
int value = realm.where(c).max(primaryKeyFied).intValue();
return value+1;
}
为什么表为空时返回0?因为我讨厌Id的值为0,所以只需更改它。
希望它能帮助别人
//generates primary key
public static int getNextKey(RealmQuery realmQuery, String fieldName) {
try {
Number number = realmQuery.max(fieldName);
if (number != null) {
return number.intValue() + 1;
} else {
return 1;
}
} catch (ArrayIndexOutOfBoundsException e) {
return 1;
}
}
范例
int id = RealmDbHelper.getNextKey(realm.where(RealmDocument.class), RealmDocument.FIELD_DOCUMENT_ID)
realmObject.setId(id);
realm.insert(realmObject);
你能提高你文章的可读性吗?您想要实现什么,出了什么问题?很明显,我们使用查询获取数据,特别是元素的ID,所以我的问题是如何使用ID从数据库中获取对象,并且realm提供所有ID,相同的值=0,为什么不是自动递增呢!由于
maximunit
方法已被弃用,现在我们需要使用.max(“id”).intValue()
代替。当对象未在数据库中创建时,我们需要为ArrayIndexOutOfBoundsException添加一个try and catch。请尝试{return realm.where(object).max(“id”).intValue()+1;}catch(ArrayIndexOutOfBoundsException e){return 0;}如果数据库中没有该类型的对象,max(“id”)
返回null
。因此,在调用intValue()
之前,您必须检查这一点,如果第一个id为null
,则返回第一个id。有人能给我解释一下原因吗?为什么这个东西没有开箱即用?@NeonWarge因为自动递增的主键在分布式环境中不起作用,而分布式环境正是上述代码适合我的领域,但我第一次得到了NPE而不是AIOOBE。顺便说一句,我使用了long
作为主键“id”。这段代码很旧-你使用的是什么版本的领域?我使用的是2.2.0,我想知道如果高优先级在等待列表中4年,他们什么时候会遇到中等优先级的问题