Uzyskiwanie dostępu do danych za pomocą funkcji DAO dla sal

Gdy do przechowywania danych aplikacji używasz biblioteki trwałości sal, z zapisanymi danymi, definiując obiekty dostępu do danych (DAO). Każdy DAO obejmuje metody zapewniające abstrakcyjny dostęp do bazy danych aplikacji. Podczas kompilowania , Sala automatycznie generuje implementowane przez Ciebie zasoby DAO.

Przez używanie DAO do uzyskiwania dostępu do bazy danych aplikacji zamiast konstruktorów zapytań lub bezpośrednich zapytań, można zachować oddzielenie , o znaczeniu krytycznym tej zasady. DAO ułatwia też imitowanie dostępu do bazy danych, przetestowanie aplikacji.

Anatomia DAO

Każdy DAO możesz zdefiniować jako interfejs lub klasę abstrakcyjną. Podstawowe zazwyczaj korzystasz z interfejsu. W obu przypadkach musisz zawsze dodaj do aktywnych użytkowników adnotacje przy użyciu @Dao. DAO nie mają właściwości, ale definiują co najmniej jedną metodę interakcji z danymi w bazie danych aplikacji.

Poniższy kod to przykład prostego DAO, który definiuje metody wstawianie, usuwanie i wybieranie obiektów User w bazie danych sal:

Kotlin

@Dao
interface UserDao {
    @Insert
    fun insertAll(vararg users: User)

    @Delete
    fun delete(user: User)

    @Query("SELECT * FROM user")
    fun getAll(): List<User>
}

Java

@Dao
public interface UserDao {
    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);

    @Query("SELECT * FROM user")
    List<User> getAll();
}

Istnieją 2 typy metod DAO definiujących interakcje z bazami danych:

  • Wygodne metody wstawiania, aktualizowania i usuwania wierszy w bazie danych bez konieczności pisania kodu SQL.
  • metody zapytań, które pozwalają napisać własne zapytanie SQL służące do interakcji z w bazie danych.

W sekcjach poniżej pokazujemy, jak używać obu typów metod DAO do określać interakcje z bazami danych, których potrzebuje Twoja aplikacja.

Metody wygodne

W pokoju znajdują się adnotacje o udogodnieniach dla definiowania prostych metod wprowadzania, aktualizacji i usuwania bez konieczności pisania instrukcji SQL.

Jeśli chcesz zdefiniować bardziej złożone wstawienia, aktualizacje lub usuwanie albo jeśli , aby wysyłać zapytania dotyczące danych w bazie danych, użyj metody zapytań.

Wstaw

Adnotacja @Insert umożliwia: zdefiniować metody wstawiania parametrów do odpowiedniej tabeli w w bazie danych. Ten kod zawiera przykłady prawidłowych metod @Insert, które wstaw do bazy danych co najmniej 1 obiekt User:

Kotlin

@Dao
interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertUsers(vararg users: User)

    @Insert
    fun insertBothUsers(user1: User, user2: User)

    @Insert
    fun insertUsersAndFriends(user: User, friends: List<User>)
}

Java

@Dao
public interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public void insertUsers(User... users);

    @Insert
    public void insertBothUsers(User user1, User user2);

    @Insert
    public void insertUsersAndFriends(User user, List<User> friends);
}

Każdy parametr metody @Insert musi być wystąpieniem Room klasa encji danych z adnotacją @Entity lub zbiór instancji klas encji danych, z których każda wskazuje bazę danych. Po wywołaniu metody @Insert sala wstawia każdy przekazać instancję encji do odpowiedniej tabeli bazy danych.

Jeśli metoda @Insert otrzymuje pojedynczy parametr, może zwrócić long , która jest nową wartością rowId dla wstawionego produktu. Jeśli parametr to tablica lub kolekcja, a następnie zwraca tablicę lub kolekcję z long wartości, przy czym każdą z wartości jako rowId dla jednej z wstawionych elementy(ów). Więcej informacji o zwracaniu wartości rowId znajdziesz w dokumentacji, dokumentacja usługi @Insert i dokumentację SQLite dla parametru rowid .

Aktualizuj

Adnotacja @Update umożliwia: definiowania metod, które aktualizują określone wiersze w tabeli bazy danych. Polub Metody @Insert, metody @Update akceptują wystąpienia encji danych jako parametry. Poniżej znajduje się przykład metody @Update, która próbuje wykonać zaktualizuj co najmniej 1 obiekt User w bazie danych:

Kotlin

@Dao
interface UserDao {
    @Update
    fun updateUsers(vararg users: User)
}

Java

@Dao
public interface UserDao {
    @Update
    public void updateUsers(User... users);
}

Sala używa podstawowego klucz do zaliczenia testu instancji encji do wierszy w bazie danych. Jeśli nie ma wiersza z taką samą wartością klucz podstawowy, sala nie wprowadza żadnych zmian.

Metoda @Update może opcjonalnie zwrócić wartość int wskazującą liczbę z wierszy, które zostały zaktualizowane.

Usuń

Adnotacja @Delete umożliwia: zdefiniować metody usuwania określonych wierszy z tabeli bazy danych. Polub Metody @Insert, metody @Delete akceptują wystąpienia encji danych jako parametry. Poniżej znajduje się przykład metody @Delete, która próbuje wykonać usuń z bazy danych jeden lub więcej obiektów User:

Kotlin

@Dao
interface UserDao {
    @Delete
    fun deleteUsers(vararg users: User)
}

Java

@Dao
public interface UserDao {
    @Delete
    public void deleteUsers(User... users);
}

Sala używa podstawowego klucz do zaliczenia testu instancji encji do wierszy w bazie danych. Jeśli nie ma wiersza z taką samą wartością klucz podstawowy, sala nie wprowadza żadnych zmian.

Metoda @Delete może opcjonalnie zwrócić wartość int wskazującą liczbę Liczba usuniętych wierszy: .

Metody zapytań

Adnotacja @Query umożliwia: napisać instrukcje SQL i udostępnić je jako metody DAO. Użyj tych metod, aby: zapytań o dane z bazy danych aplikacji lub gdy chcesz wykonać wstawienia, aktualizacje i usuwania.

Sala weryfikuje zapytania SQL podczas kompilacji. Oznacza to, że jeśli wystąpi problem zamiast błędu środowiska wykonawczego, występuje błąd kompilacji.

Proste zapytania

Ten kod określa metodę, która za pomocą prostego zapytania SELECT zwróci wszystkie obiekty User w bazie danych:

Kotlin

@Query("SELECT * FROM user")
fun loadAllUsers(): Array<User>

Java

@Query("SELECT * FROM user")
public User[] loadAllUsers();

W sekcjach poniżej pokazujemy, jak zmodyfikować ten przykład do typowego zastosowania przypadków.

Zwraca podzbiór kolumn tabeli

Zwykle wystarczy zwrócić tylko podzbiór kolumn z tabeli. którego dotyczy zapytanie. Na przykład interfejs użytkownika może wyświetlać tylko pierwsze nazwisko użytkownika, a nie wszystkie informacje o nim. Aby zapisać zasobów i usprawnienia wykonywania zapytania, używaj jedynie zapytań wymagane pola.

Za pomocą opcji Room zwracany jest prosty obiekt z dowolnego zapytania, o ile możesz zmapować zestaw kolumn z wynikami na zwrócony obiekt. Na przykład: może zdefiniować następujący obiekt przechowujący imię i nazwisko użytkownika:

Kotlin

data class NameTuple(
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)

Java

public class NameTuple {
    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    @NonNull
    public String lastName;
}

Następnie możesz zwrócić ten prosty obiekt z metody zapytania:

Kotlin

@Query("SELECT first_name, last_name FROM user")
fun loadFullName(): List<NameTuple>

Java

@Query("SELECT first_name, last_name FROM user")
public List<NameTuple> loadFullName();

Rozumie, że zapytanie zwraca wartości parametrów first_name i last_name i że te wartości mogą być zmapowane na pola w tabeli NameTuple zajęcia. Jeśli zapytanie zwraca kolumnę, która nie jest mapowana na pole Pokój wyświetli ostrzeżenie.

Przekazywanie prostych parametrów do zapytania

W większości przypadków metody DAO muszą akceptować parametry, aby mogły wykonywać operacje filtrowania. Sala obsługuje użycie parametrów metody jako powiązania i parametry w zapytaniach.

Na przykład poniższy kod definiuje metodę, która zwraca wszystkich użytkowników powyżej określonego wieku:

Kotlin

@Query("SELECT * FROM user WHERE age > :minAge")
fun loadAllUsersOlderThan(minAge: Int): Array<User>

Java

@Query("SELECT * FROM user WHERE age > :minAge")
public User[] loadAllUsersOlderThan(int minAge);

Możesz też przekazać wiele parametrów lub odwoływać się do tego samego parametru wiele razy. razy w zapytaniu, co pokazujemy w tym kodzie:

Kotlin

@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
fun loadAllUsersBetweenAges(minAge: Int, maxAge: Int): Array<User>

@Query("SELECT * FROM user WHERE first_name LIKE :search " +
       "OR last_name LIKE :search")
fun findUserWithName(search: String): List<User>

Java

@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
public User[] loadAllUsersBetweenAges(int minAge, int maxAge);

@Query("SELECT * FROM user WHERE first_name LIKE :search " +
       "OR last_name LIKE :search")
public List<User> findUserWithName(String search);

Przekazywanie zbioru parametrów do zapytania

Niektóre z metod DAO mogą wymagać przesłania zmiennej liczby które są znane dopiero w czasie działania. Pokój rozumie, kiedy parametr reprezentuje kolekcję i automatycznie rozwija ją w czasie działania na podstawie podanych parametrów.

Na przykład poniższy kod definiuje metodę zwracającą informacje o wszystkich użytkowników z podzbioru regionów:

Kotlin

@Query("SELECT * FROM user WHERE region IN (:regions)")
fun loadUsersFromRegions(regions: List<String>): List<User>

Java

@Query("SELECT * FROM user WHERE region IN (:regions)")
public List<User> loadUsersFromRegions(List<String> regions);

Tworzenie zapytań dotyczących wielu tabel

Niektóre zapytania mogą wymagać dostępu do wielu tabel, aby obliczyć wynik. Możesz używać klauzul JOIN w zapytaniach SQL, aby odwoływać się do więcej niż jedną tabelę.

Ten kod określa metodę, która łączy 3 tabele w celu zwrócenia książki, które są obecnie wypożyczone konkretnemu użytkownikowi:

Kotlin

@Query(
    "SELECT * FROM book " +
    "INNER JOIN loan ON loan.book_id = book.id " +
    "INNER JOIN user ON user.id = loan.user_id " +
    "WHERE user.name LIKE :userName"
)
fun findBooksBorrowedByNameSync(userName: String): List<Book>

Java

@Query("SELECT * FROM book " +
       "INNER JOIN loan ON loan.book_id = book.id " +
       "INNER JOIN user ON user.id = loan.user_id " +
       "WHERE user.name LIKE :userName")
public List<Book> findBooksBorrowedByNameSync(String userName);

Możesz również zdefiniować proste obiekty, aby zwracać podzbiór kolumn z wielu tabel połączonych, co zostało omówione w sekcji Zwracanie podzbioru tabel kolumny. Ten kod definiuje DAO z metodą, która zwraca nazwy użytkowników i nazwy wypożyczonych przez nich książek:

Kotlin

interface UserBookDao {
    @Query(
        "SELECT user.name AS userName, book.name AS bookName " +
        "FROM user, book " +
        "WHERE user.id = book.user_id"
    )
    fun loadUserAndBookNames(): LiveData<List<UserBook>>

    // You can also define this class in a separate file.
    data class UserBook(val userName: String?, val bookName: String?)
}

Java

@Dao
public interface UserBookDao {
   @Query("SELECT user.name AS userName, book.name AS bookName " +
          "FROM user, book " +
          "WHERE user.id = book.user_id")
   public LiveData<List<UserBook>> loadUserAndBookNames();

   // You can also define this class in a separate file, as long as you add the
   // "public" access modifier.
   static class UserBook {
       public String userName;
       public String bookName;
   }
}

Zwracanie wielu map

W pokoju 2.4 i nowszych możesz też wysyłać zapytania do kolumn z wielu tabel bez zdefiniowanie dodatkowej klasy danych przez napisanie metod zapytań, które zwracają multimap.

Zobacz przykład z sekcji Wykonywanie zapytań do wielu tabel. Zamiast zwracać listę instancji niestandardowej klasy danych, która przechowuje par instancji User i Book, może zwrócić mapowanie User i Book bezpośrednio z metody zapytania:

Kotlin

@Query(
    "SELECT * FROM user" +
    "JOIN book ON user.id = book.user_id"
)
fun loadUserAndBookNames(): Map<User, List<Book>>

Java

@Query(
    "SELECT * FROM user" +
    "JOIN book ON user.id = book.user_id"
)
public Map<User, List<Book>> loadUserAndBookNames();

Jeśli Twoja metoda zapytań zwraca mapę wielomapową, możesz utworzyć zapytania, które wykorzystują Klauzule GROUP BY, które pozwolą Ci wykorzystać możliwości SQL do zaawansowanych obliczeń i filtrowania. Można na przykład zmodyfikować Metoda loadUserAndBookNames(), która powoduje zwracanie tylko użytkowników z co najmniej 3 książkami wymeldowano się:

Kotlin

@Query(
    "SELECT * FROM user" +
    "JOIN book ON user.id = book.user_id" +
    "GROUP BY user.name WHERE COUNT(book.id) >= 3"
)
fun loadUserAndBookNames(): Map<User, List<Book>>

Java

@Query(
    "SELECT * FROM user" +
    "JOIN book ON user.id = book.user_id" +
    "GROUP BY user.name WHERE COUNT(book.id) >= 3"
)
public Map<User, List<Book>> loadUserAndBookNames();

Jeśli nie musisz mapować całych obiektów, możesz też zwrócić mapowania między określonych kolumn w zapytaniu, ustawiając keyColumn i Atrybuty valueColumn w adnotacji @MapInfo na metoda zapytania:

Kotlin

@MapInfo(keyColumn = "userName", valueColumn = "bookName")
@Query(
    "SELECT user.name AS username, book.name AS bookname FROM user" +
    "JOIN book ON user.id = book.user_id"
)
fun loadUserAndBookNames(): Map<String, List<String>>

Java

@MapInfo(keyColumn = "userName", valueColumn = "bookName")
@Query(
    "SELECT user.name AS username, book.name AS bookname FROM user" +
    "JOIN book ON user.id = book.user_id"
)
public Map<String, List<String>> loadUserAndBookNames();

Specjalne rodzaje zwrotów

Pokoje oferują specjalne typy zwrotów w celu integracji z innymi interfejsami API biblioteki.

Zapytania z podziałem na strony z biblioteką stronicowania

Sala obsługuje zapytania podzielone na strony dzięki integracji z Paging Biblioteka. W pokoju 2.3.0-alfa01 użytkownicy mogą zwrócić PagingSource obiektów do użycia z Pagingiem 3.

Kotlin

@Dao
interface UserDao {
  @Query("SELECT * FROM users WHERE label LIKE :query")
  fun pagingSource(query: String): PagingSource<Int, User>
}

Java

@Dao
interface UserDao {
  @Query("SELECT * FROM users WHERE label LIKE :query")
  PagingSource<Integer, User> pagingSource(String query);
}

Więcej informacji o wyborze parametrów typu dla PagingSource znajdziesz w artykule Wybierz klucz i wartość .

Bezpośredni dostęp do kursora

Jeśli logika aplikacji wymaga bezpośredniego dostępu do wierszy powrotnych, możesz napisać metod DAO zwracających Cursor Jak w tym przykładzie:

Kotlin

@Dao
interface UserDao {
    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
    fun loadRawUsersOlderThan(minAge: Int): Cursor
}

Java

@Dao
public interface UserDao {
    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
    public Cursor loadRawUsersOlderThan(int minAge);
}

Dodatkowe materiały

Więcej informacji o uzyskiwaniu dostępu do danych za pomocą DAO dla sal znajdziesz w tych dodatkowych materiałach zasoby:

Próbki

Ćwiczenia z programowania