When you use the Room persistence library to store your app's data, you interact
with the stored data by defining *data access objects*, or DAOs. Each DAO
includes methods that offer abstract access to your app's database. At compile
time, Room automatically generates implementations of the DAOs that you define.

By using DAOs to access your app's database instead of query builders or direct
queries, you can preserve [separation of
concerns](https://developer.android.com/jetpack/guide#separation-of-concerns), a critical architectural
principle. DAOs also make it easier for you to mock database access when you
[test your app](https://developer.android.com/training/data-storage/room/testing-db).

## Anatomy of a DAO

You can define each DAO as either an interface or an abstract class. For basic
use cases, you usually use an interface. In either case, you must always
annotate your DAOs with [`@Dao`](https://developer.android.com/reference/kotlin/androidx/room/Dao). DAOs
don't have properties, but they do define one or more methods for interacting
with the data in your app's database.

The following code is an example of a simple DAO that defines methods for
inserting, deleting, and selecting `User` objects in a Room database:  

### Kotlin

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

    @Delete
    fun delete(user: User)

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

### Java

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

    @Delete
    void delete(User user);

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

There are two types of DAO methods that define database interactions:

- Convenience methods that let you insert, update, and delete rows in your database without writing any SQL code.
- Query methods that let you write your own SQL query to interact with the database.

The following sections demonstrate how to use both types of DAO methods to
define the database interactions that your app needs.

## Convenience methods

Room provides convenience annotations for defining methods that perform simple
insertions, updates, and deletions without requiring you to write a SQL statement.

If you need to define more complex insertions, updates, or deletions, or if you need
to query the data in the database, use a [query method](https://developer.android.com/training/data-storage/room/accessing-data#query) instead.

### Insert

The [`@Insert`](https://developer.android.com/reference/kotlin/androidx/room/Insert) annotation lets you
define methods that insert their parameters into the appropriate table in the
database. The following code shows examples of valid `@Insert` methods that
insert one or more `User` objects into the database:  

### Kotlin

```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

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

Each parameter for an `@Insert` method must be either an instance of a [Room
data entity class](https://developer.android.com/training/data-storage/room/defining-data) annotated with
`@Entity` or a collection of data entity class instances, each of which
points to a database. When an `@Insert` method is called, Room inserts each
passed entity instance into the corresponding database table.

If the `@Insert` method receives a single parameter, it can return a `long`
value, which is the new `rowId` for the inserted item. If the parameter is an
array or a collection, then return an array or a collection
of `long` values instead, with each value as the `rowId` for one of the inserted
items. To learn more about returning `rowId` values, see the reference
documentation for the [`@Insert`](https://developer.android.com/reference/kotlin/androidx/room/Insert)
annotation and the [SQLite documentation for rowid
tables](https://www.sqlite.org/rowidtable.html).

### Update

The [`@Update`](https://developer.android.com/reference/kotlin/androidx/room/Update) annotation lets you
define methods that update specific rows in a database table. Like
`@Insert` methods, `@Update` methods accept data entity instances as parameters.
The following code shows an example of an `@Update` method that attempts to
update one or more `User` objects in the database:  

### Kotlin

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

### Java

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

Room uses the [primary
key](https://developer.android.com/training/data-storage/room/defining-data#primary-key) to match passed
entity instances to rows in the database. If there is no row with the same
primary key, Room makes no changes.

An `@Update` method can optionally return an `int` value indicating the number
of rows that were updated successfully.

### Delete

The [`@Delete`](https://developer.android.com/reference/kotlin/androidx/room/Delete) annotation lets you
define methods that delete specific rows from a database table. Like
`@Insert` methods, `@Delete` methods accept data entity instances as parameters.
The following code shows an example of a `@Delete` method that attempts to
delete one or more `User` objects from the database:  

### Kotlin

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

### Java

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

Room uses the [primary
key](https://developer.android.com/training/data-storage/room/defining-data#primary-key) to match passed
entity instances to rows in the database. If there is no row with the same
primary key, Room makes no changes.

A `@Delete` method can optionally return an `int` value indicating the number of
rows that were deleted successfully.

## Query methods

The [`@Query`](https://developer.android.com/reference/kotlin/androidx/room/Query) annotation lets you
write SQL statements and expose them as DAO methods. Use these query methods to
query data from your app's database or when you need to perform more complex
insertions, updates, and deletions.

Room validates SQL queries at compile time. This means that if there's a problem
with your query, a compilation error occurs instead of a runtime failure.

### Simple queries

The following code defines a method that uses a simple `SELECT` query to return
all the `User` objects in the database:  

### Kotlin

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

### Java

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

The following sections demonstrate how to modify this example for typical use
cases.

### Return a subset of a table's columns

Most of the time, you only need to return a subset of the columns from the table
that you are querying. For example, your UI might display just the first and
last name for a user instead of every detail about that user. To save
resources and streamline your query's execution, only query the
fields that you need.

Room lets you return a simple object from any of your queries as long as
you can map the set of result columns onto the returned object. For example, you
can define the following object to hold a user's first and last name:  

### Kotlin

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

### Java

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

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

Then, you can return that simple object from your query method:  

### Kotlin

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

### Java

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

Room understands that the query returns values for the `first_name` and
`last_name` columns and that these values can be mapped onto the fields in the
`NameTuple` class. If the query returns a column that doesn't map onto a field
in the returned object, Room displays a warning.

### Pass simple parameters to a query

Most of the time, your DAO methods need to accept parameters so that they can
perform filtering operations. Room supports using method parameters as bind
parameters in your queries.

For example, the following code defines a method that returns all the users
above a certain age:  

### Kotlin

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

### Java

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

You can also pass multiple parameters or reference the same parameter multiple
times in a query, as demonstrated in the following code:  

### Kotlin

```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

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

### Pass a collection of parameters to a query

Some of your DAO methods might require you to pass in a variable number of
parameters that is not known until runtime. Room understands when a parameter
represents a collection and automatically expands it at runtime based on the
number of parameters provided.

For example, the following code defines a method that returns information about
all the users from a subset of regions:  

### Kotlin

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

### Java

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

### Query multiple tables

Some of your queries might require access to multiple tables to calculate the
result. You can use `JOIN` clauses in your SQL queries to reference more than
one table.

The following code defines a method that joins three tables together to return
the books that are currently on loan to a specific user:  

### Kotlin

```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

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

You can also define simple objects to return a subset of columns from multiple
joined tables, as discussed in the [Return a subset of a table's
columns](https://developer.android.com/training/data-storage/room/accessing-data#return-subset) section. The following code defines a DAO with a method that
returns the names of users and the names of the books that they have borrowed:  

### Kotlin

```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

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

### Return a multimap

In Room 2.4 and higher, you can also query columns from multiple tables without
defining an additional data class by writing query methods that return a
[multimap](https://en.wikipedia.org/wiki/Multimap).

Consider the example from the [Query multiple tables](https://developer.android.com/training/data-storage/room/accessing-data#multiple-tables) section.
Instead of returning a list of instances of a custom data class that holds
pairings of `User` and `Book` instances, you can return a mapping of `User` and
`Book` directly from your query method:  

### Kotlin

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

### Java

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

When your query method returns a multimap, you can write queries that use
`GROUP BY` clauses, letting you take advantage of SQL's capabilities for
advanced calculations and filtering. For example, you can modify your
`loadUserAndBookNames()` method to only return users with three or more books
checked out:  

### Kotlin

```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

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

If you don't need to map entire objects, you can also return mappings between
specific columns in your query by setting the
[`keyColumn`](https://developer.android.com/reference/kotlin/androidx/room/MapInfo#keyColumn()) and
[`valueColumn`](https://developer.android.com/reference/kotlin/androidx/room/MapInfo#valueColumn()) attributes
in a [`@MapInfo`](https://developer.android.com/reference/kotlin/androidx/room/MapInfo) annotation on your
query method:  

### Kotlin

```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

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

## Special return types

Room provides some special return types for integration with other API
libraries.

### Paginated queries with the Paging library

Room supports paginated queries through integration with the [Paging
library](https://developer.android.com/topic/libraries/architecture/paging). In Room 2.3.0-alpha01 and
higher, DAOs can return
[`PagingSource`](https://developer.android.com/reference/kotlin/androidx/paging/PagingSource) objects for use
with [Paging 3](https://developer.android.com/topic/libraries/architecture/paging/v3-overview).  

### Kotlin

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

### Java

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

For more information about choosing type parameters for a `PagingSource`, see
[Select key and value
types](https://developer.android.com/topic/libraries/architecture/paging/v3-paged-data#key-value).

### Direct cursor access

If your app's logic requires direct access to the return rows, you can write
your DAO methods to return a [`Cursor`](https://developer.android.com/reference/kotlin/android/database/Cursor)
object, as shown in the following example:  

### Kotlin

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

### Java

```java
@Dao
public interface UserDao {
    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
    public Cursor loadRawUsersOlderThan(int minAge);
}
```
| **Caution:** We don't recommend using the Cursor API, because it doesn't guarantee that the rows exist or what values the rows contain. Only use this functionality if you already have code that expects a cursor and that you can't refactor easily.

## Additional resources

To learn more about accessing data using Room DAOs, see the following additional
resources:

### Samples

- [Android Sunflower](https://github.com/android/sunflower)

### Codelabs

- Android Room with a View [(Java)](https://developer.android.com/codelabs/android-room-with-a-view) [(Kotlin)](https://developer.android.com/codelabs/android-room-with-a-view-kotlin)