java 在Android Java中通过主键获取Realm对象的正确方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38109905/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 03:07:53  来源:igfitidea点击:

Proper way to get Realm object by its primary key in Android Java

javaandroidrealm

提问by Loudenvier

I wonder if there's a proper way to retrieve an object given its primary key in Realm for Android. I know the method objectForPrimaryKeydoes exists in Swift but there seems to be no such counterpart in Realm for Android. I really think that doing realm.where(EventInfo.class).equalTo("id", eventInfo.id).findFirst();looks like a lot of waste (at least it is not wrist-friendly). Am I missing some method? I'm Currently using Realm 1.0.1

我想知道在 Realm for Android 中是否有一种正确的方法来检索给定主键的对象。我知道该方法objectForPrimaryKey确实存在于 Swift 中,但在 Realm for Android 中似乎没有这样的对应方法。我真的认为这样做realm.where(EventInfo.class).equalTo("id", eventInfo.id).findFirst();看起来很浪费(至少它对手腕不友好)。我错过了一些方法吗?我目前使用的是 Realm 1.0.1

回答by EpicPandaForce

This is why I have a Realm repository like this one (which I wrote)

这就是为什么我有一个像这样的 Realm 存储库(我写的)

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

and I inherit a method called findOne(realm, id);like

我继承了一个名为findOne(realm, id);like

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

But yes, by default, it's realm.where(CalendarEvent.class).equalTo("id", id).findFirst();

但是,是的,默认情况下,它是 realm.where(CalendarEvent.class).equalTo("id", id).findFirst();

回答by Loudenvier

I've ended up creating a helper class for this. I'll be using it until the Realm team implement these methods. I've named the class Find(you can rename it the way you like, since naming things and cache invalidation are the hardest things in computer science). I think it's better to use this than to call where().equalTo()passing the name of the primary key as a string value. This way you're sure to use the correct primary key field. Here is the code:

我最终为此创建了一个助手类。在 Realm 团队实现这些方法之前,我将一直使用它。我已经命名了这个类Find(你可以按照你喜欢的方式重命名它,因为命名事物和缓存失效是计算机科学中最难的事情)。我认为使用它比调用where().equalTo()将主键的名称作为字符串值传递更好。这样您就可以确保使用正确的主键字段。这是代码:

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

Usage is straightforward:

用法很简单:

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

It'll return null if there is no primary key for the given object or if the object is not found. I considered throwing an exception if there were no primary key, but decided it was overkill.

如果给定对象没有主键或找不到该对象,它将返回 null。我考虑过在没有主键的情况下抛出异常,但认为这是矫枉过正。

I was really sad Java generics are not as powerful as C# generics, because I really, really would love to call the method as follows:

我真的很伤心 Java 泛型不如 C# 泛型强大,因为我真的,真的很想调用如下方法:

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

And believe me I tried! I've searched everywhere how to get a method's generic type return value. When it proved impossible, since Java erases the generic methods, I tried creating a generic class and use:

相信我,我试过了!我到处搜索如何获取方法的泛型类型返回值。当它被证明不可能时,由于 Java 删除了泛型方法,我尝试创建一个泛型类并使用:

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

And all the possible permutations to no avail! So I gave up...

而所有可能的排列都无济于事!所以我放弃了...

Note: I've only implemented String and Long versions of Find.byKeybecause Realm accepts only String and Integral data as primary keys, and Long will allow querying for Byte and Integer fields too (I hope!)

注意:我只实现了 String 和 Long 版本,Find.byKey因为 Realm 只接受 String 和 Integral 数据作为主键,Long 也允许查询 Byte 和 Integer 字段(我希望!)

回答by Tim

Am I missing some method?

我错过了一些方法吗?

Nope. As beeender mentioned, it's not implemented currently. Progress/discussion can be tracked here.

不。正如 beeender 所提到的,它目前尚未实施。可以在此处跟踪进度/讨论。

A helper function could look like this

辅助函数可能如下所示

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

It a class-specific method here because each class could have a different primary key type. You have to pass a realm instance to it that you manage in the calling class.

这是一个特定于类的方法,因为每个类都可以有不同的主键类型。您必须将在调用类中管理的领域实例传递给它。

回答by Enrico Bruno Del Zotto

With the new Realm you can access to the primary key of your table using the schema of your DB in this manner:

使用新的 Realm,您可以使用数据库的架构以这种方式访问​​表的主键:

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

I'm not very expert in annotation, I've tried to read value of @PrimaryKeyat runtime by reflection, using getAnnotation()on fields, but values are always null, maybe because of @Retention(RetentionPolicy.CLASS).

我在注释方面不是很专业,我尝试@PrimaryKey通过反射在运行时读取值,在getAnnotation()字段上使用,但值总是null,可能是因为@Retention(RetentionPolicy.CLASS).