Accesso ai dati utilizzando i DAO delle stanze

Quando usi la libreria di persistenza della stanza per archiviare i dati dell'app, interagisci con i dati archiviati definendo oggetti di accesso ai dati o DAO. Ogni DAO include metodi che offrono accesso astratto al database dell'app. Al momento della compilazione volta, Room genera automaticamente le implementazioni dei DAO che definisci.

Usando DAO per accedere al database dell'app anziché tramite Query Builder o dirigere query, puoi conservare la separazione di sicurezza, un'architettura di base dell'IA. I DAO semplificano anche la simulazione dell'accesso al database quando testare l'app.

Anatomia di un DAO

Puoi definire ogni DAO come interfaccia o classe astratta. Per le versioni di base casi d'uso, di solito usi un'interfaccia. In ogni caso, devi sempre annota i DAO con @Dao. DAO non hanno proprietà, ma definiscono uno o più metodi di interazione con i dati del database dell'app.

Il codice riportato di seguito è un esempio di un DAO semplice che definisce i metodi per inserimento, eliminazione e selezione di User oggetti in un database delle stanze:

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

Esistono due tipi di metodi DAO che definiscono le interazioni con i database:

  • Metodi pratici che ti consentono di inserire, aggiornare ed eliminare righe senza scrivere codice SQL.
  • Metodi di query che ti consentono di scrivere la tua query SQL per interagire con per configurare un database.

Le seguenti sezioni mostrano come utilizzare entrambi i tipi di metodi DAO per e definire le interazioni con il database necessarie alla tua app.

Metodi pratici

La stanza virtuale fornisce annotazioni pratiche per la definizione di metodi semplici inserimenti, aggiornamenti ed eliminazioni senza che sia necessario scrivere un'istruzione SQL.

Se hai bisogno di definire inserimenti, aggiornamenti o eliminazioni più complessi o per eseguire query sui dati nel database, utilizza invece un metodo query.

Inserisci

L'annotazione @Insert ti consente di definire metodi che inseriscono i propri parametri nella tabella appropriata del per configurare un database. Il seguente codice mostra esempi di metodi @Insert validi che Inserisci uno o più oggetti User nel database:

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

Ogni parametro per un metodo @Insert deve essere un'istanza di una room classe entità di dati annotata con @Entity o una raccolta di istanze della classe entità dati, ciascuna delle quali punta a un database. Quando viene chiamato un metodo @Insert, la stanza virtuale inserisce ogni ha passato l'istanza dell'entità alla tabella di database corrispondente.

Se il metodo @Insert riceve un singolo parametro, può restituire un long che corrisponde al nuovo rowId per l'elemento inserito. Se il parametro è un un array o una raccolta, quindi restituisce un array o una raccolta di long valori, con ogni valore come rowId per uno dei valori inseriti elementi. Per scoprire di più sulla restituzione dei valori rowId, consulta il riferimento documentazione di @Insert e la documentazione di SQLite per rowid tabelle.

Aggiorna

L'annotazione @Update ti consente di definiscono metodi che aggiornano righe specifiche in una tabella di database. Mi piace I metodi @Insert, @Update accettano le istanze entità dati come parametri. Il codice seguente mostra un esempio di metodo @Update che tenta di aggiorna uno o più oggetti User nel database:

Kotlin

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

Java

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

La stanza virtuale utilizza il chiave affinché corrisponda a quella passata istanze di entità in righe nel database. Se non è presente una riga con lo stesso chiave primaria, la stanza non apporta modifiche.

Un metodo @Update può restituire facoltativamente un valore int che indica il numero di righe aggiornate correttamente.

Elimina

L'annotazione @Delete ti consente di definiscono i metodi che eliminano righe specifiche da una tabella di database. Mi piace I metodi @Insert, @Delete accettano le istanze entità dati come parametri. Il codice seguente mostra un esempio di metodo @Delete che tenta di Elimina uno o più oggetti User dal database:

Kotlin

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

Java

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

La stanza virtuale utilizza il chiave affinché corrisponda a quella passata istanze di entità in righe nel database. Se non è presente una riga con lo stesso chiave primaria, la stanza non apporta modifiche.

Un metodo @Delete può restituire facoltativamente un valore int che indica il numero di righe eliminate correttamente.

Metodi di query

L'annotazione @Query ti consente di scrivere istruzioni SQL ed esporle come metodi DAO. Utilizza questi metodi di query per interroga i dati dal database della tua app o quando devi eseguire attività inserimenti, aggiornamenti ed eliminazioni.

La stanza virtuale convalida le query SQL al momento della compilazione. Ciò significa che se c'è un problema della query, si verifica un errore di compilazione anziché un errore di runtime.

Query semplici

Il seguente codice definisce un metodo che utilizza una semplice query SELECT per restituire tutti gli oggetti User nel database:

Kotlin

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

Java

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

Le seguenti sezioni mostrano come modificare questo esempio per l'utilizzo tipico d'uso diversi.

Restituire un sottoinsieme delle colonne di una tabella

La maggior parte delle volte devi restituire solo un sottoinsieme delle colonne della tabella su cui stai eseguendo query. Ad esempio, nella UI potrebbero essere visualizzati solo i primi due il cognome di un utente invece di ogni suo dettaglio. Per risparmiare risorse e semplifichino l'esecuzione della query, esegui la query solo campi necessari.

Room ti consente di restituire un oggetto semplice da qualsiasi query, purché puoi mappare l'insieme di colonne dei risultati all'oggetto restituito. Ad esempio, può definire l'oggetto seguente in cui inserire nome e cognome di un utente:

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

Quindi, puoi restituire questo semplice oggetto dal tuo metodo di query:

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

La stanza virtuale comprende che la query restituisce valori per first_name e last_name colonne e che questi valori possono essere mappati ai campi in NameTuple corso. Se la query restituisce una colonna che non corrisponde a un campo nell'oggetto restituito, la stanza virtuale mostra un avviso.

Trasmettere parametri semplici a una query

La maggior parte delle volte, i metodi DAO devono accettare parametri in modo da poter eseguire operazioni di filtro. La stanza virtuale supporta l'utilizzo di parametri del metodo come associazione parametri nelle tue query.

Ad esempio, il seguente codice definisce un metodo che restituisce tutti gli utenti al di sopra di una determinata età:

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

Puoi anche passare più parametri o fare riferimento a più parametri allo stesso volte in una query, come illustrato nel codice che segue:

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

Passare una raccolta di parametri a una query

Alcuni dei tuoi metodi DAO potrebbero richiedere il passaggio di un numero variabile conosciuti fino al runtime. La stanza capisce quando un parametro rappresenta una raccolta e la espande automaticamente in fase di runtime in base di parametri forniti.

Ad esempio, il seguente codice definisce un metodo che restituisce informazioni su per tutti gli utenti di un sottoinsieme di regioni:

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

Eseguire query su più tabelle

Alcune query potrebbero richiedere l'accesso a più tabelle per calcolare il o il risultato finale. Puoi utilizzare le clausole JOIN nelle query SQL per fare riferimento a più di una tabella.

Il codice seguente definisce un metodo che unisce tre tabelle da restituire i libri attualmente in prestito a uno specifico utente:

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

È inoltre possibile definire oggetti semplici per restituire un sottoinsieme di colonne da più come descritto nella sezione Restituisci un sottoinsieme dei dati di una tabella Colonne. Il seguente codice definisce un DAO con un metodo che restituisce i nomi degli utenti e i nomi dei libri che hanno preso in prestito:

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

Restituire una mappa multipla

Nella stanza 2.4 e successive, puoi anche eseguire query sulle colonne da più tabelle senza la definizione di una classe di dati aggiuntiva scrivendo metodi di query che restituiscono un multimap.

Considera l'esempio della sezione Esegui query su più tabelle. Invece di restituire un elenco di istanze di una classe di dati personalizzata che contiene accoppiamenti di User e Book istanze, puoi restituire una mappatura di User e Book direttamente dal tuo metodo di query:

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

Quando il metodo di query restituisce una mappa multipla, puoi scrivere query che utilizzano GROUP BY, che ti consentono di sfruttare le funzionalità di SQL per calcoli e filtri avanzati. Ad esempio, puoi modificare loadUserAndBookNames() metodo per restituire solo gli utenti con tre o più libri check-out:

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

Se non è necessario mappare interi oggetti, puoi anche restituire mappature tra colonne specifiche della query impostando keyColumn e Attributi valueColumn in un'annotazione @MapInfo sul tuo :

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

Tipi di resi speciali

Room fornisce alcuni tipi di resi speciali per l'integrazione con altre API librerie.

Query impaginate con la libreria Paging

La stanza virtuale supporta le query impaginate tramite l'integrazione con il libreria di Google. Nella stanza 2.3.0-alpha01 e superiore, i DAO possono restituire PagingSource oggetti da utilizzare con Paging 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);
}

Per ulteriori informazioni sulla scelta dei parametri del tipo per un PagingSource, consulta Seleziona chiave e valore tipi di annunci personalizzati.

Accesso diretto al cursore

Se la logica della tua app richiede l'accesso diretto alle righe restituite, puoi scrivere i tuoi metodi DAO per restituire un Cursor come mostrato nell'esempio seguente:

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

Risorse aggiuntive

Per scoprire di più sull'accesso ai dati utilizzando i DAO delle stanze, consulta le di risorse:

Campioni

Codelab