web-dev-qa-db-fra.com

Comportement du royaume et de l'incrémentation automatique (Android)

J'essaie d'obtenir des données de Realm en utilisant un identifiant comme référence. Cependant, lors de la recherche d'un ID, j'ai constaté que Realm me donnait le même ID pour tous les éléments (ID de 0). Pourquoi l'incrémentation automatique de l'ID ne se produit-elle pas lorsque j'utilise l'annotation @PrimaryKey sur l'ID du modèle?

Voici la classe raccourcie pour le modèle:

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

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

Et la requête que j'exécute est: realm.where(Child_pages.class).equalTo("id_cp",page_id).findFirst()

26
Bachlet Tansime

Le royaume ne prend actuellement pas en charge l'incrémentation automatique des clés primaires. Cependant, vous pouvez facilement l'implémenter vous-même en utilisant quelque chose comme:

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

J'espère que cela peut vous aider à démarrer. 

65
Bachlet Tansime

La liaison Java ne prend pas encore en charge les clés primaires, mais elle figure dans la feuille de route et avec une priorité élevée - voir: https://groups.google.com/forum/#!topic/realm-Java/6hFqdyoH67w Pour contourner le problème, vous pouvez utiliser ce morceau de code pour générer des clés:

int key;
try {
  key = realm.where(Child_pages.class).max("id").intValue() + 1;
} catch(ArrayIndexOutOfBoundsException ex) {
 key = 0;
}

J'utilise singleton factory pour générer des clés primaires en tant que solution plus générique et offrant de meilleures performances (inutile de rechercher max("id") à chaque fois grâce à AtomicInteger).

Il y a une longue discussion dans Realm Git Hub si vous avez besoin de plus de contexte: Documentez comment définir un identifiant d'incrémentation automatique?

10
zacheusz

Comme déjà mentionné, l'incrémentation automatique n'est pas encore prise en charge.

Mais pour ceux qui utilisent kotlin et qui veulent avoir un comportement auto-incrémenté avec le royaume, voici une des possibilités:

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
Vinicius Lima

si votre identifiant est long, alors: 

val nextId = bgRealm.where(Branch::class.Java).max("localId") as Long + 1
0
LEMUEL ADANE

Voici une solution générique. Personnellement, je crée une classe nommée RealmUtils et j'ajoute ce type de méthodes: 

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

Pourquoi je retourne 0 quand la table est vide? Parce que je déteste les identifiants avec 0 comme valeur, alors changez-les simplement .. J'espère que cela aidera quelqu'un.

0
Mabrouki Fakhri
//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;
        }
    }

Exemple

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

Malheureusement, je ne peux pas commenter d'autres réponses, mais j'aimerais ajouter à la réponse de Vinicius .

Tout d'abord, vous ne devriez pas ouvrir une nouvelle instance de domaine lorsque vous recherchez une clé primaire, en particulier lorsque vous ne la fermez pas, car cela ajoute au nombre maximal de descripteurs de fichier possible.

Deuxièmement, bien que ce soit une préférence, vous ne devriez pas avoir de types primitifs (ou d’équivalents d’objets) nullables (dans Kotlin), car cela ajoute une obligation redondante de vérifier la nullité.

Troisièmement, puisque vous utilisez kotlin, vous pouvez simplement définir une méthode d'extension à la classe Realm, telle que:

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

Étant donné que toutes les instances RealmObject sont RealmModel et que même les objets qui ne sont pas suivis par Realm sont toujours des instances RealmModel, ils seront donc disponibles partout où vous utiliserez vos classes liées au domaine. L'équivalent Java serait:

static long getNextId(RealmModel object, Realm realm, String idField)
{
    long count = realm.where(object.class).max(idField);
    return count + 1;
}

Note d'édition tardive: Il est préférable de ne pas utiliser cette approche si vous traitez avec des données qui pourraient provenir de sources extérieures, telles que d'autres bases de données ou du Web, car cela entraînerait des conflits entre les données de votre base de données interne. Au lieu de cela, vous devriez utiliser max([id field name]). Voir les extraits précédents, je les ai déjà modifiés pour tenir compte de cette modification.

0
Dragas