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: