2016-06-29 29 views
6

Android用Realmでプライマリキーを指定してオブジェクトを取得する方法が適切かどうか疑問です。私はobjectForPrimaryKeyがSwiftに存在するメソッドを知っていますが、Android用のRealmにはそのようなものは存在しないようです。私は実際にrealm.where(EventInfo.class).equalTo("id", eventInfo.id).findFirst();をやっていることが多くの無駄に思えると思う(少なくともそれは手首に優しいものではない)。私はいくつかの方法が欠けていますか?私は現在レルム1.0.1を使用していますAndroidのプライマリキーでRealmオブジェクトを取得する適切な方法Java

+1

はい、これは長いコード行です:https://github.com/realm/realm-java/issues/2166に関する未解決の問題があります。今のところ、長い線を使うか、ヘルパー関数を作成する必要があると思います。 – beeender

+1

@beeender多くのORMで 'getObjectByKey (Tキー)'を使用していましたが(RealmはORMではありませんが、それ以上です)、Realmですでに何かが行われている可能性があると思いました。たぶんそれは最適化することさえできるかもしれません。私はまた、単一のオブジェクトが予想される場合(おそらく複数のものが見つかった場合にはスローと例外)、findFirst()の代わりに.single()というメソッドを提案します。 realm-javaの問題にこの提案を追加する必要がありますか? – Loudenvier

+0

はい、どうぞ! githubの問題を議論し続けることで、私たちが追跡するのがずっと楽になります。ありがとう! – beeender

答えて

2

私はいくつかの方法がありますか?

いいえ。上記のとおり、現在実装されていません。進捗状況/ディスカッションはhereで追跡できます。各クラスは異なる主キーのタイプを持っている可能性があるため、

ヘルパー関数は、この

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

また、ここでクラス固有のメソッドのようになります。呼び出しクラスで管理する領域インスタンスを渡す必要があります。

7

私は

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

(私が書いた)このようなレルムリポジトリを持っていると私は

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

ようfindOne(realm, id);と呼ばれる方法を継承しかし、はい、デフォルトでは、それはrealm.where(CalendarEvent.class).equalTo("id", id).findFirst();だ理由です

+0

私はこれを念頭に置いていましたが、getIdがすべてのモデルで長時間を返すというわけではないので、私の答えを変更しました。どのように対処していますか? –

+0

私は 'StringRealmRepositoryImpl'または' NoIdRealmRepositoryImpl'からケースに応じて拡張します – EpicPandaForce

+0

私はリポジトリパターンが気に入らないので、私はORMを直接使うのが好きです。私の経験では、リポジトリはどんな助けよりも痛みがあります。 ORMは一種のリポジトリです。オブジェクトモデルに直接結びついた基になるデータへのアクセスとクエリが可能です。 Martin Fowlerは、リポジトリを「ドメインとデータマッピング層の間を仲介するオブジェクト」として定義しました。それはORMがIMHOのためのものです:-)だから、おそらくRealm自体をサブクラス化し、欠けているメソッドを追加します:-) – Loudenvier

3

私はこのためのヘルパークラスを作成しました。 Realmチームがこれらのメソッドを実装するまで、私はそれを使用します。私はクラスをFindと命名しました(命名とキャッシュの無効化はthe hardest things in computer scienceなので好きなように名前を変更できます)。 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); 
    } 
} 

使い方は簡単です:

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

指定されたオブジェクトまたはオブジェクトが見つからない場合は主キーが存在しない場合にはnullを返します。プライマリキーがなければ例外をスローすることを考えましたが、それは過度のものであると判断しました。

私は次のように私は本当に、本当にメソッドを呼び出すことが大好きだので、Javaのジェネリックは、C#のジェネリックほど強力ではありません、本当に悲しかった:

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

そして、私が試した私を信じて!私はメソッドのジェネリック型の戻り値を取得する方法をどこでも検索しました。無駄に

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

そして、すべての可能な順列:それは不可能証明した場合には、Javaが一般的な方法を消去するので、私は、ジェネリッククラスと使用を作成してみました!だから私はあきらめました...

注:RealmはStringとIntegralデータを主キーとして受け入れ、LongはByteフィールドとIntegerフィールドも照会することができるため、StringとLongバージョンの実装はFind.byKeyです。 !あなたは、このようにあなたのDBのスキーマを使用して、テーブルの主キーにアクセスできる新しいレルムに)

+1

'(クラス)(ParameterizedType)getClass 'new TypeToken (){};'のような型パラメトリックな匿名サブクラスでのみ動作します。例えば、実際には 'List 'を返すこともできます。それはGSONの仕組みですが、 'EventInfo.class'よりも入力が難しい – EpicPandaForce

1

:私は注釈では非常に専門家ではない

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

、私が試しました実行時にリフレクションによって@PrimaryKeyという値を読み取り、フィールドにgetAnnotation()を使用しますが、値は常にnullで、おそらく@Retention(RetentionPolicy.CLASS)のためです。

関連する問題