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

时间:2015-05-04 10:50:52

标签: java android realm

我尝试使用ID作为参考从Realm获取数据。但是,在查询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()

8 个答案:

答案 0 :(得分:65)

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

我希望能让你开始。

答案 1 :(得分:10)

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作为更通用的解决方案,性能更佳(每次都max("id")无需查询AtomicInteger)。

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

答案 2 :(得分: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
        }
}}

答案 3 :(得分:0)

如果你的身份证长,那么:

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

答案 4 :(得分:0)

可悲的是,我无法对其他答案发表评论,但我想添加到Vinicius` answer

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

其次,虽然这是一个偏好,但你不应该将原始类型(或对象等价物)作为nullables(在 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])。请参阅前面的代码段,我已修改它们以适应此编辑。

答案 5 :(得分:0)

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

答案 6 :(得分: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);

答案 7 :(得分:-1)

//编辑

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

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

//原始答案

我只想分享我解决此问题的尝试,因为我不想一直传递主键值。首先,我创建了一个Database-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;
    }
}

如需进一步的建议,请随时在下面发表评论。