2016-06-29 8 views
6

Zastanawiam się, czy istnieje właściwy sposób na odzyskanie obiektu, biorąc pod uwagę jego klucz podstawowy w obszarze Realm dla Androida. Wiem, że metoda objectForPrimaryKey istnieje w Swift, ale wydaje się, że nie ma takiego odpowiednika w Realm dla Androida. Naprawdę myślę, że robienie realm.where(EventInfo.class).equalTo("id", eventInfo.id).findFirst(); wygląda jak dużo odpadów (przynajmniej nie jest przyjazne dla nadgarstków). Czy brakuje mi jakiejś metody? Aktualnie używam Realm 1.0.1Właściwy sposób na uzyskanie obiektu Realm za pomocą klucza podstawowego w Androidzie Java

+1

Tak, to długa linia kodu :) Mamy otwarty problem dla niego https://github.com/realm/realm-java/issues/2166. Na razie myślę, że musisz użyć długiej linii lub utworzyć dla niej funkcję pomocnika. – beeender

+1

@beeender Przyzwyczaiłem się do 'getObjectByKey (klucz T)' w wielu ORMach (nie że Realm to ORM, to więcej), więc pomyślałem, że może być coś już zrobionego w Królestwie. Może to nawet można zoptymalizować. Chciałbym również zasugerować metodę o nazwie .single() zamiast findFirst() dla przypadków, w których oczekiwany jest pojedynczy obiekt (prawdopodobnie rzucanie i wyjątek, jeśli znaleziono więcej niż jeden). Czy powinienem dodać tę sugestię w kwestiach realm-java? – Loudenvier

+0

Tak, proszę! Prowadzenie dyskusji w sprawie Githuba znacznie ułatwia nam śledzenie. Dzięki! – beeender

Odpowiedz

2

Czy brakuje mi jakiejś metody?

Nie. Jak wspomniałem, Beeender nie jest w tej chwili implementowany. Postęp/dyskusję można śledzić here.

Funkcja pomocnika mógłby wyglądać następująco

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

on metoda klasy specyficzne tutaj, ponieważ każda klasa może mieć inny podstawowy rodzaj klucza. Musisz przekazać do niej instancję realm, którą zarządzasz w klasie wywołującej.

7

Dlatego mam repozytorium Realm podobny do tego (co pisałem)

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

i dziedziczyć metody nazywanej findOne(realm, id); jak

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

Ale tak, domyślnie jest to realm.where(CalendarEvent.class).equalTo("id", id).findFirst();

+0

Miałem to na uwadze, ale potem zmieniłem odpowiedź, ponieważ nie jest to dane, że getId zwraca długi czas dla wszystkich modeli, jak sobie z tym radzisz? –

+0

Rozciąga się od 'StringRealmRepositoryImpl' lub' NoIdRealmRepositoryImpl' w zależności od przypadku – EpicPandaForce

+0

Nie podoba mi się wzór repozytorium, wolę bezpośrednio korzystać z ORM. Z mojego doświadczenia wynika, że ​​repozytoriom jest więcej bólu niż jakiejkolwiek pomocy. ORM jest rodzajem repozytorium, ponieważ umożliwia dostęp i zapytanie do podstawowych danych bezpośrednio związanych z modelem obiektu. Martin Fowler zdefiniował repozytoria jako "obiekt, który pośredniczy między domeną a warstwami mapowania danych." To jest dokładnie to, co ORM dla IMHO :-) Więc prawdopodobnie będę podklasą samej Rzeczy i doda brakujące metody :-) – Loudenvier

3

Skończyło się tworzenie klasy pomocnika dla tego. Będę go używał, dopóki zespół Królestwa nie wdroży tych metod. Nazwałem klasę Find (możesz zmienić jej nazwę tak, jak lubisz, ponieważ nazywanie rzeczy i unieważnianie pamięci podręcznej to the hardest things in computer science). Myślę, że lepiej jest użyć tego niż wywołać where().equalTo() przekazując nazwę klucza podstawowego jako wartość ciągu. W ten sposób na pewno użyjesz właściwego pola klucza podstawowego. Oto kod:

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

Użycie jest bardzo proste:

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

To będzie powrót null, jeśli nie ma klucz podstawowy dla danego obiektu lub jeśli obiekt nie został znaleziony. Zastanawiałem się nad wyrzuceniem wyjątku, jeśli nie było klucza głównego, ale zdecydowałem, że to przesada.

byłem bardzo smutny rodzajowych Java nie są tak wydajne jak C# rodzajowych, bo naprawdę chciałbym wywołać metodę w następujący sposób:

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

I wierzcie mi próbowałem! Przeszukałem wszędzie, jak uzyskać zwrotną wartość typową dla metody. Kiedy okazało się niemożliwe, ponieważ Java kasuje metody rodzajowe, Próbowałem tworzenia klasy rodzajowy i zastosowanie:

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

i wszystkie możliwe permutacje bezskutecznie! Więc zrezygnowałem ...

Uwaga: Zaimplementowałem tylko wersje String i Long o numerze Find.byKey, ponieważ Realm akceptuje tylko dane String i Integral jako klucze podstawowe, a Long pozwala na sprawdzanie pól Byte i Integer (mam nadzieję !)

+1

' (Class ) (ParameterizedType) getClass() .getGenericSuperclass()). GetActualTypeArguments() [0]; 'działa tylko z podklasami anonimowymi typu parametrycznego, takimi jak' nowy TypeToken () {}; 'może on również zwrócić' List 'na przykład na przykład działa na przykład GSON, ale nieco trudniej go wpisać niż "EventInfo.class" – EpicPandaForce

1

z nowym Realm można uzyskać dostęp do klucza podstawowego tabeli, stosując schemat swojego DB w ten sposób:

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

Nie jestem ekspertem w adnotacji, Próbowałam odczytaj wartość @PrimaryKey w środowisku wykonawczym przez odbicie, używając getAnnotation() w polach, ale wartości są zawsze null, być może z powodu @Retention(RetentionPolicy.CLASS).

Powiązane problemy