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

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

我正在尝试使用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 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年,他们什么时候会遇到中等优先级的问题