web-dev-qa-db-fra.com

Moyen approprié pour obtenir l'objet Realm par sa clé primaire dans Android Java

Je me demande s'il existe un moyen approprié de récupérer un objet compte tenu de sa clé primaire dans Realm pour Android. Je sais que la méthode objectForPrimaryKey existe dans Swift mais il ne semble pas y avoir d'équivalent dans Realm pour Android. Je pense vraiment que faire realm.where(EventInfo.class).equalTo("id", eventInfo.id).findFirst(); ressemble à beaucoup de gaspillage (au moins, il n'est pas adapté aux poignets). Manque-je une méthode? J'utilise actuellement Realm 1.0.1

12
Loudenvier

C'est pourquoi j'ai un référentiel Realm comme celui-ci (que j'ai écrit)

public class CalendarEventRepositoryImpl
        extends LongRealmRepositoryImpl<CalendarEvent>
        implements CalendarEventRepository {
    public CalendarEventRepositoryImpl() {
        super(CalendarEvent.class);
    }

    @Override
    public Long getId(CalendarEvent calendarEvent) {
        return calendarEvent.getId();
    }

    public void setId(CalendarEvent calendarEvent, Long id) {
        calendarEvent.setId(id);
    }

    public String getIdFieldName() {
        return CalendarEventFields.ID;
    }
}

et j'hérite d'une méthode appelée findOne(realm, id); comme

CalendarEvent event = calendarEventRepository.findOne(realm, id);

Mais oui, par défaut, c'est realm.where(CalendarEvent.class).equalTo("id", id).findFirst();

7
EpicPandaForce

J'ai fini par créer une classe d'aide pour cela. Je vais l'utiliser jusqu'à ce que l'équipe Realm implémente ces méthodes. J'ai nommé la classe Find (vous pouvez la renommer comme vous le souhaitez, car nommer les choses et invalider le cache sont les choses les plus difficiles en informatique ). Je pense qu'il vaut mieux utiliser cela que d'appeler where().equalTo() en passant le nom de la clé primaire comme une valeur de chaîne. De cette façon, vous êtes sûr d'utiliser le champ de clé primaire correct. Voici le code:

import Java.util.Hashtable;
import io.realm.Realm;
import io.realm.RealmModel;
import io.realm.RealmObjectSchema;

public final class Find {
    // shared cache for primary keys
    private static Hashtable<Class<? extends RealmModel>, String> primaryKeyMap = new Hashtable<>();

    private static String getPrimaryKeyName(Realm realm, Class<? extends RealmModel> clazz) {
        String primaryKey = primaryKeyMap.get(clazz);
        if (primaryKey != null)
            return primaryKey;
        RealmObjectSchema schema = realm.getSchema().get(clazz.getSimpleName());
        if (!schema.hasPrimaryKey())
            return null;
        primaryKey = schema.getPrimaryKey();
        primaryKeyMap.put(clazz, primaryKey);
        return primaryKey;
    }

    private static <E extends RealmModel, TKey> E findByKey(Realm realm, Class<E> clazz, TKey key) {
        String primaryKey = getPrimaryKeyName(realm, clazz);
        if (primaryKey == null)
            return null;
        if (key instanceof String)
            return realm.where(clazz).equalTo(primaryKey, (String)key).findFirst();
        else
            return realm.where(clazz).equalTo(primaryKey, (Long)key).findFirst();
    }

    public static <E extends RealmModel> E byKey(Realm realm, Class<E> clazz, String key) {
        return findByKey(realm, clazz, key);
    }

    public static <E extends RealmModel> E byKey(Realm realm, Class<E> clazz, Long key) {
        return findByKey(realm, clazz, key);
    }
}

L'utilisation est simple:

// now you can write this
EventInfo eventInfo = Find.byKey(realm, EventInfo.class, eventInfoId);
// instead of this
EventInfo eventInfo = realm.where(EventInfo.class).equalTo("id", eventInfo.id).findFirst();

Il retournera null s'il n'y a pas de clé primaire pour l'objet donné ou si l'objet n'est pas trouvé. J'ai envisagé de lever une exception s'il n'y avait pas de clé primaire, mais j'ai décidé que c'était exagéré.

J'étais vraiment triste Java ne sont pas aussi puissants que les génériques C #, parce que j'aimerais vraiment, vraiment appeler la méthode comme suit:

Find.byKey<EventInfo>(realm, eventInfoId);

Et croyez-moi, j'ai essayé! J'ai cherché partout comment obtenir la valeur de retour de type générique d'une méthode. Quand cela s'est avéré impossible, puisque Java efface les méthodes génériques, j'ai essayé de créer une classe générique et d'utiliser:

(Class<T>)(ParameterizedType)getClass()
        .getGenericSuperclass()).getActualTypeArguments()[0];

Et toutes les permutations possibles en vain! Alors j'ai abandonné ...

Remarque: je n'ai implémenté que les versions String et Long de Find.byKey car Realm n'accepte que les données String et Integral comme clés primaires, et Long permettra également d'interroger les champs Byte et Integer (j'espère!)

6
Loudenvier

Suis-je en train de manquer une méthode?

Nan. Comme l'a mentionné Beeender, il n'est pas mis en œuvre actuellement. Les progrès/discussions peuvent être suivis ici .

Une fonction d'aide pourrait ressembler à ceci

public class Cat extends RealmObject {

    @PrimaryKey
    private int id;
    private String name;

    public Cat getByPrimaryKey(Realm realm, int id) {
        return realm.where(getClass()).equalTo("id", id).findFirst();
    }
}

C'est une méthode spécifique à la classe ici car chaque classe peut avoir un type de clé primaire différent. Vous devez lui passer une instance de domaine que vous gérez dans la classe appelante.

4
Tim

Avec le nouveau domaine, vous pouvez accéder à la clé primaire de votre table en utilisant le schéma de votre base de données de la manière suivante:

private String load(Class realmClass) {
  return mRealm.getSchema().get(realmClass.getSimpleName()).getPrimaryKey();
}

Je ne suis pas très expert en annotation, j'ai essayé de lire la valeur de @PrimaryKey Lors de l'exécution par réflexion, en utilisant getAnnotation() sur les champs, mais les valeurs sont toujours null, peut-être à cause de @Retention(RetentionPolicy.CLASS).

1