【问题标题】:Realm and auto increment Behavior (Android)领域和自动增量行为 (Android)
【发布时间】:2015-07-13 17:30:46
【问题描述】:

我正在尝试使用 ID 作为参考从 Realm 获取数据。但是,在查询 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_pages.class).equalTo("id_cp",page_id).findFirst()

【问题讨论】:

  • 您能提高帖子的可读性吗?你想达到什么目标,出了什么问题?
  • 很明显,我们使用查询特别是元素的 ID 来获取数据,所以我的问题是如何使用 ID 从数据库中获取我的对象,而领域给出了所有的 ID,相同的值 =0,为什么不是自动增量!

标签: java android realm


【解决方案1】:

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

我希望这可以帮助您入门。

【讨论】:

  • 由于maximumInt方法已被弃用,现在我们需要使用.max("id").intValue()
  • 当对象未在数据库中创建时,我们需要为 ArrayIndexOutOfBoundsException 添加一个 try 和 catch。尝试 { return realm.where(object).max("id").intValue() + 1; } catch (ArrayIndexOutOfBoundsException e) { 返回 0; }
  • 如果数据库中没有该类型的对象,max("id") 返回null。所以你必须在调用intValue()之前检查一下,如果是null,则返回第一个id。
  • 谁能给我解释一下这个原因?为什么这个东西不是开箱即用的?
  • @NeonWarge 因为自动增量主键在 Realm Sync 分布式环境中不起作用
【解决方案2】:

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

我使用singleton factory for generating primary keys 作为更通用的解决方案,具有更好的性能(由于AtomicInteger,无需每次都查询max("id"))。

如果您需要更多上下文,请在 Realm Git Hub 中进行长时间讨论:Document how to set an auto increment id?

【讨论】:

  • 上面的代码对我来说很好用,但是我第一次得到了 NPE 而不是 AIOOBE。顺便说一句,我使用 long 作为主键“id”。
  • 这个 sn-p 很老了 - 你用的是什么版本的领域?
  • 我使用的是 2.2.0
  • 我想知道如果高优先级在等待列表中 4 年,他们什么时候会处理中优先级问题
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    这是一个通用的解决方案,我个人创建了一个名为 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,所以只需更改它。 希望对某人有所帮助。

    【讨论】:

      【解决方案5】:

      如果你的 ID 是长的,那么:

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

      【讨论】:

        【解决方案6】:

        很遗憾,我无法评论其他答案,但我想添加到Vinicius` answer

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

        其次,尽管这是一种偏好,但您不应该将原始类型(或对象等价物)作为可空值(在 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;
        }
        

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

        【讨论】:

          【解决方案7】:
          //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);
          

          【讨论】:

            【解决方案8】:

            // 编辑

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

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

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

            【讨论】:

              猜你喜欢
              • 2015-09-22
              • 2017-03-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多