Java 领域和自增行为 (Android)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30028282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:01:19  来源:igfitidea点击:

Realm and auto increment Behavior (Android)

javaandroidrealm

提问by Bachlet Tansime

I'm trying to get data from Realm using an ID as a reference. However, when querying for an ID, I've found that Realm is giving me the same ID for all elements (ID of 0). Why doesn't the ID auto-increment when I use the @PrimaryKeyannotation on the model's ID?

我正在尝试使用 ID 作为参考从 Realm 获取数据。但是,在查询 ID 时,我发现 Realm 为所有元素提供了相同的 ID(ID 为 0)。为什么@PrimaryKey在模型 ID 上使用注释时 ID 不会自动增加?

Here's the shortened class for the model:

这是模型的缩短类:

public class Child_pages extends RealmObject {
    @PrimaryKey
    private int id_cp;

    private int id;
    private String day;
    private int category_id;

And the query I'm executing is: realm.where(Child_pages.class).equalTo("id_cp",page_id).findFirst()

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

回答by Bachlet Tansime

Realm currently doesn't support auto incrementing primary keys. However you can easily implement it yourself using something like:

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;
    }
}

I hope that can get you started.

我希望这能让你开始。

回答by zacheusz

The Java binding does not support primary keys yet, but it's on the roadmap and with high priority - see: https://groups.google.com/forum/#!topic/realm-java/6hFqdyoH67w. As a workaround you can use this piece of code for generating keys:

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;
}

I use singleton factory for generating primary keysas a more generic solution with better performance (no need to query for max("id")every time thanks to AtomicInteger).

我使用单例工厂来生成主键作为具有更好性能的更通用的解决方案(max("id")由于无需每次都查询AtomicInteger)。

There is a long discussion in Realm Git Hub if you need more context: Document how to set an auto increment id?

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

回答by kejith

// EDIT

// 编辑

I found this new solution on this problem

我在这个问题上找到了这个新的解决方案

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

// Original Answer

// 原始答案

I just wanted to share my attempt on solving this Problem, because i don't want to pass a primary Key value all the time. First i created a Database-Class to handle the storage of a RealmObject.

我只是想分享我解决这个问题的尝试,因为我不想一直传递主键值。首先,我创建了一个数据库类来处理 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
        }
    });
}

After creating the database-class i created an Interface to distinguish between Objects with a Primary Key and without.

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

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

Now you will just need to edit this code of the previous execute method

现在您只需要编辑之前执行方法的这段代码

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

With this solution the database logic will still be in one class and this class can passed down to every class which needs to write into the database.

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

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;
    }
}

For further suggestions feel free to leave a comment below.

如需更多建议,请随时在下面发表评论。

回答by LEMUEL ADANE

if your Id is Long then:

如果您的 ID 为 Long,则:

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

回答by Vinicius Lima

As already mentioned, auto-increment isn't supported yet.

如前所述,尚不支持自动增量。

But for those who use kotlinand wants to have an auto-increment behavior with realm, this is one of the possibilities:

但是对于那些使用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
        }
}}

回答by Dragas

Sadly, I can't comment on other answers, but I'd like to add to Vinicius` answer.

遗憾的是,我无法对其他答案发表评论,但我想补充Vinicius 的答案

First, you shouldn't open a new realm instance, when looking for primary key, especially when you don't close them, as this adds to maximum possible file descriptor count.

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

Secondly, although this is a preference, you shouldn't have primitive types (or object equivalents) as nullables (in Kotlin), as this adds redundant requirement to check nullability.

其次,虽然这是一个偏好,但您不应该将原始类型(或对象等价物)作为可空类型(在Kotlin 中),因为这增加了检查可空性的冗余要求。

Third, since you're using kotlin, you can just define an extension method to Realmclass, such as:

第三,由于您使用的是 kotlin,您只需定义一个扩展方法即可Realm,例如:

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

Since all RealmObjectinstances are RealmModel, and even objects that aren't tracked by Realm are still RealmModelinstances, therefore it will be available where ever you use your realm related classes. Java equivalent would be:

由于所有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;
}

Late edit note: You're better off not using this approach if you're dealing with data that might come from outside sources, such as other databases or the web, because that WILL result in collisions between data in your internal database. Instead you should use max([id field name]). See the previous snippets, I already modified them to accommodate for this edit.

后期编辑注意:如果您正在处理可能来自外部来源(例如其他数据库或网络)的数据,最好不要使用这种方法,因为这会导致内部数据库中的数据之间发生冲突。相反,您应该使用max([id field name]). 请参阅前面的片段,我已经对其进行了修改以适应此编辑。

回答by Mabrouki Fakhri

Here is a genereic solution, personnaly I create a class named RealmUtils and I add this type of methods :

这是一个通用的解决方案,我个人创建了一个名为 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;
}

Why I return 0 when the table is empty ? Because I hate Id's with 0 as value, so just change it. Hope it help someone.

为什么我在表为空时返回 0?因为我讨厌以 0 为值的 Id,所以只需更改它。希望它可以帮助某人。

回答by Pavel Poley

//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;
        }
    }

Example

例子

int id = RealmDbHelper.getNextKey(realm.where(RealmDocument.class), RealmDocument.FIELD_DOCUMENT_ID)
    realmObject.setId(id);
    realm.insert(realmObject);