Поведение и автоматическое приращение (Android)

java android realm

19293 просмотра

8 ответа

Я пытаюсь получить данные из области, используя идентификатор в качестве ссылки. Однако при запросе идентификатора я обнаружил, что Realm дает мне один и тот же идентификатор для всех элементов (идентификатор 0). Почему не происходит автоматическое увеличение идентификатора, когда я использую @PrimaryKeyаннотацию для идентификатора модели?

Вот сокращенный класс для модели:

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()

Автор: Bachlet Tansime Источник Размещён: 17.05.2019 03:12

Ответы (8)


65 плюса

В настоящее время область не поддерживает автоматическое увеличение первичных ключей. Однако вы можете легко реализовать это самостоятельно, используя что-то вроде:

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

Я надеюсь, что вы можете начать.

Автор: Bachlet Tansime Размещён: 04.05.2015 01:31

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

Я использую фабрику синглтонов для генерации первичных ключей в качестве более общего решения с лучшей производительностью (нет необходимости max("id")каждый раз запрашивать, благодаря AtomicInteger).

В Realm Git Hub долго обсуждается вопрос о том, нужно ли вам больше контекста: документ, как установить идентификатор автоматического приращения?

Автор: zacheusz Размещён: 17.03.2016 08:09

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
        }
}}
Автор: Vinicius Lima Размещён: 05.02.2017 09:26

0 плюса

если ваш идентификатор длинный, то:

val nextId = bgRealm.where(Branch::class.java).max("localId") as Long + 1
Автор: LEM Adane Размещён: 06.11.2016 11:25

0 плюса

К сожалению, я не могу комментировать другие ответы, но я хотел бы добавить к ответу Виниция .

Во-первых, вам не следует открывать новый экземпляр области при поиске первичного ключа, особенно если вы не закрываете его, поскольку это увеличивает максимально возможное количество дескрипторов файлов.

Во-вторых, хотя это предпочтение, у вас не должно быть примитивных типов (или эквивалентных объектов) в качестве обнуляемых (в 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]). Смотрите предыдущие фрагменты, я уже изменил их, чтобы приспособить для этого редактирования.

Автор: Dragas Размещён: 28.04.2017 08:44

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 в качестве значения, поэтому просто измените его. Надеюсь, это поможет кому-то.

Автор: Mabrouki Fakhri Размещён: 02.08.2018 03:01

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);
Автор: Pavel Poley Размещён: 05.02.2019 09:19

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

Теперь вам просто нужно отредактировать этот код предыдущего метода 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;
    }
}

Для дальнейших предложений не стесняйтесь оставлять комментарии ниже.

Автор: kejith Размещён: 21.10.2016 02:29
Вопросы из категории :
32x32