Skip to content

Most visited

Recently visited

navigation

Accessing data using Room DAOs

To access your app's data using the Room persistence library, you work with data access objects, or DAOs. This set of Dao objects forms the main component of Room, as each DAO includes methods that offer abstract access to your app's database.

By accessing a database using a DAO class instead of query builders or direct queries, you can separate different components of your database architecture. Furthermore, DAOs allow you to easily mock database access as you test your app.

A DAO can be either an interface or an abstract class. If it's an abstract class, it can optionally have a constructor that takes a RoomDatabase as its only parameter. Room creates each DAO implementation at compile time.

Note: Room doesn't support database access on the main thread unless you've called allowMainThreadQueries() on the builder because it might lock the UI for a long period of time. Asynchronous queries—queries that return instances of LiveData or Flowable—are exempt from this rule because they asynchronously run the query on a background thread when needed.

Define methods for convenience

There are multiple convenience queries that you can represent using a DAO class. This document includes several common examples.

Insert

When you create a DAO method and annotate it with @Insert, Room generates an implementation that inserts all parameters into the database in a single transaction.

The following code snippet shows several example queries:

@Dao
public interface MyDao {
    @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);
}

If the @Insert method receives only 1 parameter, it can return a long, which is the new rowId for the inserted item. If the parameter is an array or a collection, it should return long[] or List<Long> instead.

For more details, see the reference documentation for the @Insert annotation, as well as the SQLite documentation for rowid tables.

Update

The Update convenience method modifies a set of entities, given as parameters, in the database. It uses a query that matches against the primary key of each entity.

The following code snippet demonstrates how to define this method:

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

Although usually not necessary, you can have this method return an int value instead, indicating the number of rows updated in the database.

Delete

The Delete convenience method removes a set of entities, given as parameters, from the database. It uses the primary keys to find the entities to delete.

The following code snippet demonstrates how to define this method:

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

Although usually not necessary, you can have this method return an int value instead, indicating the number of rows removed from the database.

Query for information

@Query is the main annotation used in DAO classes. It allows you to perform read/write operations on a database. Each @Query method is verified at compile time, so if there is a problem with the query, a compilation error occurs instead of a runtime failure.

Room also verifies the return value of the query such that if the name of the field in the returned object doesn't match the corresponding column names in the query response, Room alerts you in one of the following two ways:

Simple queries

@Dao
public interface MyDao {
    @Query("SELECT * FROM user")
    public User[] loadAllUsers();
}

This is a very simple query that loads all users. At compile time, Room knows that it is querying all columns in the user table. If the query contains a syntax error, or if the user table doesn't exist in the database, Room displays an error with the appropriate message as your app compiles.

Passing parameters into the query

Most of the time, you need to pass parameters into queries to perform filtering operations, such as displaying only users who are older than a certain age. To accomplish this task, use method parameters in your Room annotation, as shown in the following code snippet:

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

When this query is processed at compile time, Room matches the :minAge bind parameter with the minAge method parameter. Room performs the match using the parameter names. If there is a mismatch, an error occurs as your app compiles.

You can also pass multiple parameters or reference them multiple times in a query, as shown in the following code snippet:

@Dao
public interface MyDao {
    @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);
}

Returning subsets of columns

Most of the time, you need to get only a few fields of an entity. For example, your UI might display just a user's first name and last name, rather than every detail about the user. By fetching only the columns that appear in your app's UI, you save valuable resources, and your query completes more quickly.

Room allows you to return any Java-based object from your queries as long as the set of result columns can be mapped into the returned object. For example, you can create the following plain old Java-based object (POJO) to fetch the user's first name and last name:

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

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

Now, you can use this POJO in your query method:

@Dao
public interface MyDao {
    @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 into the fields of the NameTuple class. Therefore, Room can generate the proper code. If the query returns too many columns, or a column that doesn't exist in the NameTuple class, Room displays a warning.

Passing a collection of arguments

Some of your queries might require you to pass in a variable number of parameters, with the exact number of parameters not known until runtime. For example, you might want to retrieve information about all users from a subset of regions. Room understands when a parameter represents a collection and automatically expands it at runtime based on the number of parameters provided.

@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
    public List<NameTuple> loadUsersFromRegions(List<String> regions);
}

Observable queries

When performing queries, you'll often want your app's UI to update automatically when the data changes. To achieve this, use a return value of type LiveData in your query method description. Room generates all necessary code to update the LiveData when the database is updated.

@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
    public LiveData<List<User>> loadUsersFromRegionsSync(List<String> regions);
}

Reactive queries with RxJava

Room can also return RxJava2 Publisher and Flowable objects from the queries you define. To use this functionality, add the android.arch.persistence.room:rxjava2 artifact from the Room group into your build Gradle dependencies. You can then return objects of types defined in RxJava2, as shown in the following code snippet:

@Dao
public interface MyDao {
    @Query("SELECT * from user where id = :id LIMIT 1")
    public Flowable<User> loadUserById(int id);
}

For more details, see the Google Developers Room and RxJava article.

Direct cursor access

If your app's logic requires direct access to the return rows, you can return a Cursor object from your queries, as shown in the following code snippet:

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

Caution: It's highly discouraged to work with the Cursor API because it doesn't guarantee whether the rows exist or what values the rows contain. Use this functionality only if you already have code that expects a cursor and that you can't refactor easily.

Querying multiple tables

Some of your queries might require access to multiple tables to calculate the result. Room allows you to write any query, so you can also join tables. Furthermore, if the response is an observable data type, such as Flowable or LiveData, Room watches all tables referenced in the query for invalidation.

The following code snippet shows how to perform a table join to consolidate information between a table containing users who are borrowing books and a table containing data about books currently on loan:

@Dao
public interface MyDao {
    @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 return POJOs from these queries. For example, you can write a query that loads a user and their pet's name as follows:

@Dao
public interface MyDao {
   @Query("SELECT user.name AS userName, pet.name AS petName "
          + "FROM user, pet "
          + "WHERE user.id = pet.user_id")
   public LiveData<List<UserPet>> loadUserAndPetNames();

   // You can also define this class in a separate file, as long as you add the
   // "public" access modifier.
   static class UserPet {
       public String userName;
       public String petName;
   }
}
This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)