Tworzenie odwołań do złożonych danych za pomocą funkcji Pokoje

Pokoje umożliwiają konwersję między typami podstawowymi i pudełkowymi , ale nie zezwala na odwołania do obiektów między elementami. Ten dokument Wyjaśnia, jak używać konwerterów typów i dlaczego pokój nie obsługuje obiektu odwołania.

Używanie konwerterów typów

Czasami aplikacja musi przechowywać niestandardowy typ danych w pojedynczej bazie danych. . Obsługujesz typy niestandardowe, udostępniając tagi konwersji typu, które są instruujących Room konwertowanie typów niestandardowych na i ze znanych typów, Pomieszczenie może być nieodwracalne. Konwertery typu możesz określić za pomocą @TypeConverter.

Załóżmy, że chcesz zachować wystąpienia ciągu Date w do bazy danych sal. W pokoju nie wiadomo, jak utrwalić Date obiekty, dlatego potrzebujesz aby zdefiniować konwertery typów:

Kotlin

class Converters {
  @TypeConverter
  fun fromTimestamp(value: Long?): Date? {
    return value?.let { Date(it) }
  }

  @TypeConverter
  fun dateToTimestamp(date: Date?): Long? {
    return date?.time?.toLong()
  }
}

Java

public class Converters {
  @TypeConverter
  public static Date fromTimestamp(Long value) {
    return value == null ? null : new Date(value);
  }

  @TypeConverter
  public static Long dateToTimestamp(Date date) {
    return date == null ? null : date.getTime();
  }
}

W tym przykładzie zdefiniowano 2 metody konwertera typu: jedną, która konwertuje: Date do obiektu Long i drugiego, który wykonuje odwrotną konwersję z obiektu Long do Date. Pokój wie, jak zachować obiekty Long, więc może użyć aby zachować Date obiektów.

Następnie dodaj @TypeConverters adnotacja do klasy AppDatabase, dzięki której pokój wie o konwertocie zdefiniowaną klasę:

Kotlin

@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
  abstract fun userDao(): UserDao
}

Java

@Database(entities = {User.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
  public abstract UserDao userDao();
}

Po zdefiniowaniu konwerterów typu niestandardowego możesz użyć typu niestandardowego w encje i DAO w taki sam sposób jak w przypadku typów podstawowych:

Kotlin

@Entity
data class User(private val birthday: Date?)

@Dao
interface UserDao {
  @Query("SELECT * FROM user WHERE birthday = :targetDate")
  fun findUsersBornOnDate(targetDate: Date): List<User>
}

Java

@Entity
public class User {
  private Date birthday;
}

@Dao
public interface UserDao {
  @Query("SELECT * FROM user WHERE birthday = :targetDate")
  List<User> findUsersBornOnDate(Date targetDate);
}

W tym przykładzie Sala może wszędzie używać konwertera zdefiniowanego typu, ponieważ dodał adnotacje AppDatabase z @TypeConverters. Możesz też wybrać typ użytkowników, którzy dokonali konwersji w konkretne jednostki lub użytkowników DAO, dodając adnotacje do @Entity lub @Dao zajęcia z @TypeConverters.

Inicjowanie konwertera typu elementu sterującego

Zazwyczaj usługa Sala obsługuje wystąpienia konwerterów typu za Ciebie. Pamiętaj jednak: czasami konieczne może być przekazanie dodatkowych zależności do konwertera typów klas, co oznacza, że aplikacja musi bezpośrednio kontrolować inicjowanie. konwerterów danego typu. W takim przypadku dodaj do klasy konwertera adnotację @ProvidedTypeConverter:

Kotlin

@ProvidedTypeConverter
class ExampleConverter {
  @TypeConverter
  fun StringToExample(string: String?): ExampleType? {
    ...
  }

  @TypeConverter
  fun ExampleToString(example: ExampleType?): String? {
    ...
  }
}

Java

@ProvidedTypeConverter
public class ExampleConverter {
  @TypeConverter
  public Example StringToExample(String string) {
    ...
  }

  @TypeConverter
  public String ExampleToString(Example example) {
    ...
  }
}

Oprócz zadeklarowania klasy konwersji w tym języku (@TypeConverters) możesz użyć funkcji RoomDatabase.Builder.addTypeConverter(). aby przekazać instancję klasy konwertera do funkcji RoomDatabase kreator:

Kotlin

val db = Room.databaseBuilder(...)
  .addTypeConverter(exampleConverterInstance)
  .build()

Java

AppDatabase db = Room.databaseBuilder(...)
  .addTypeConverter(exampleConverterInstance)
  .build();

Wyjaśnienie, dlaczego sala nie zezwala na odwołania do obiektów

Podsumowanie: Sala nie zezwala na odwołania do obiektów między klasami encji. Zamiast tego musisz: wyraźnie żądać danych, których potrzebuje aplikacja.

Mapowanie relacji z bazy danych do odpowiedniego modelu obiektu jest powszechne i świetnie działa po stronie serwera. Nawet po wczytaniu programu z wykorzystaniem różnych pól, serwer nadal działa dobrze.

Po stronie klienta ten typ leniwego ładowania jest jednak niemożliwy, ponieważ zwykle występuje w wątku UI i wysyła zapytania o informacje na dysku w interfejsie użytkownika. powoduje poważne problemy z wydajnością. Wątek UI zwykle ma ok. 16 ms na obliczenie i rysowanie zaktualizowanego układu aktywności, więc nawet jeśli trwa tylko 5 ms, prawdopodobnie aplikacja zabraknie czasu narysować ramkę, co powoduje zauważalne problemy wizualne. Zapytanie może zająć nawet mieć więcej czasu na realizację, jeśli równolegle odbywa się inna transakcja. gdy urządzenie jest uruchomione inne zadania wymagające dużej ilości dysku. Jeśli nie używasz leniwego ale aplikacja pobiera więcej danych, niż jest potrzebna, dlatego tworzy pamięć. problemów z konsumpcją treści.

W przypadku mapowań obiektów i relacji obiektów decyzyjnych te decyzje zwykle podejmują deweloperzy, więc mogą zrobić wszystko, co jest najlepsze w danym przypadku. Zwykle deweloperzy zdecydować się na współdzielenie modelu między aplikacją a UI. To rozwiązanie: można dobrze skalować, ponieważ wraz z upływem czasu interfejs zmienia się, tworzy problemy, które są trudne do przewidzenia i debugowania przez programistów.

Weźmy na przykład interfejs, który wczytuje listę obiektów Book z każdą książką ma obiekt Author. Możesz początkowo projektować zapytania tak, aby używać wczytuję, aby instancje Book pobrały autora. Pierwsze pobranie wartości pole author wysyła zapytanie do bazy danych. Po jakimś czasie zdajesz sobie sprawę, musisz też wyświetlać imię i nazwisko autora w interfejsie aplikacji. Masz dostęp do: Jak widać w tym fragmencie kodu:

Kotlin

authorNameTextView.text = book.author.name

Java

authorNameTextView.setText(book.getAuthor().getName());

Jednak ta pozornie niewinna zmiana powoduje, że dane w tabeli Author pojawiają się w wynikach wyszukiwania. w wątku głównym.

Jeśli zapytasz o autora z wyprzedzeniem, trudno będzie zmienić jak dane są wczytywane, gdy już ich nie potrzebujesz. Na przykład, jeśli aplikacja Interfejs nie musi już wyświetlać informacji o aplikacji Author – aplikacja się wczytuje danych, których już nie wyświetla, i tym samym marnuje cenne miejsce w pamięci. W przypadku Twojej aplikacji wydajność spada jeszcze bardziej, jeśli klasa Author odwołuje się do innej tabeli, na przykład Books.

Aby odwoływać się do wielu elementów jednocześnie za pomocą Pokoju, utwórz zamiast tego plik funkcja POJO, która obejmuje każdą encję, a następnie napisz zapytanie, które łączy odpowiednie tabeli. Ten dobrze uporządkowany model w połączeniu z rozbudowanym zapytaniem pokoju umożliwia aplikacji zużywanie mniejszej ilości zasobów podczas wczytywania danych, zwiększając wydajność aplikacji i wrażenia użytkowników.