In this chapter of the Room basics tutorial, we are going to talk about the main part of Room, which is the creation of the DAO, the Database and the Entity.
- DAO stands for Data Access Object, which is an interface, that contains the queries to access the database. It is annotated with @DAO
- Database represents the database. Because it holds a connection to the SQLite database, all operations are executed through it. It is annotated with @Database.
- Entity represents a table in the Room database, which should be annotatad with the @Entity keyword.
If you haven’t done the previous chapter, where we prepared the starter project, then from GitHub you can download it for this chapter.
Step 1 – Implementation of DAO
DAO is used to access our data on our device, what we have created using Room. DAO contains all of the methods, what we can use to manipulate these data. It means, these objects can contain all of the CRUD (Create, Read, Update, Delete) methods/queries, what is needed for our project. (eg. get a filtered list)
These methods specify the SQL queries. The compiler checks them and generate queries using a convinient way of annotations, like @Insert.
DAO can be implemented as abstract class or as an interface. In our project we will create it as an interface.
Room has coroutine support as well, allowing us to do the queries in a background thread, which are has the suspend modifier. Then we can call them from a coroutine or from another suspension function.
Create the DAO interface
So, after a short introduction, we are going to create the DAO and the needed methods.
As always, we are going to create for these files a new package. To follow the guideline of Google and the MVVM design pattern, we are going to call this new package as “repository”. It means, that these files will be responsible to directly communicate with the data stored on our device or online (like Firebase or a web service).
Then again with the right mouse button, click on the repository package. Select New, and the Kotlin/File class option.
The code of the ToDoDao::interface
Before we go deeply into the explanation of the DAO, copy and paste the below code into the ToDoDao::interface.
So, Let’s walk through it.
- The @DAO annotation tells Room thet this is a DAO class
- The @Insert annotation again helps Room to identify this method as an insert operation.
The selected onConflict strategy will repleace the already existing ToDo with the new one. You can check the strategies under this link: Conflict Strategies
A suspending function is just a regular Kotlin function with an additional suspend modifier which indicates that the function can suspend the execution of a coroutine. Later on, we are going to run these method in a background thread.
We can use the ToDo data class. So, we don’t have to convert it to other types, we can use directly as an argument.
- Similarly to the insert method, we are going to have here the updateToDo() as a suspend function which is annotated with @Update.
- To delete one item, we can use the @Delete annotation.
- We can use in the DAO directly SQL queries as well. We can provide it using the @Query annotation, thenafter in the brackets, we can provide the SQL query as a String parameter. It allows us to implement complex queries.
Step 2 – Annotation of the ToDo data class
If you have done the previous chapter, then you should remember, that we have created there the ToDo data class. This class holds the data and it has some properties. In our case, these properties are going to be the columns in the SQL table. But let’s not run ahead.
The ToDo data class will represent a table inside of the SQL database. From Room’s point of view, this class will be an Entity. As we have talked about, this will represent a table in the Room database and we have to annotate it with @Entity.
First, open the ToDo data class from the model package. Then, before the header of the class, paste the below Room annotation.
@Entity(tableName = “ToDo”)
After the @Entity in the brackets, we should determine the name of the table. In our case it is the same like the name of the data class, but if you want, then you can specify here a different table name as well.
The primary key
Next, we are going to determine the primary key. This has to be always uniqe, because Room can separate the items using this key. In our case the toDoId property will be the primary key. To specify it, we can use the @PrimaryKey annotation.
So, before the property paste the below line.
@PrimaryKey(autoGenerate = true)
In the brackets, we can tell Room that this id has to be autogenerated. It means, that the toDoId will be automatically created, and increased by one when a new item has been inserted.
The question is, that how can we tell for Room, that we don’t want to specify this toDoId, when we want to create a new ToDo object. In this case just type 0 (zero) in the position of the toDoId.
The name of the columns
The third annotation, what we are going to use in this data class is the @ColumnInfo. It specifies the name of the column in the table, if we want it to be different from the name of the member variable. So, annotate all of the rest property with @ColumnInfo like below.
@ColumnInfo(name = “title”)
Finally the ToDo data class should like this.
ToDo data class
Step 3 – Implementation of the database
Next step is to create the database. The Room database contains the database holder and serves as the main point for the underlying connection to our application’s persisted, relational data.
First, we need to create a new kotlin file. So, click on the repository package with the right mouse button, select New, then the Kotlin file/class option. In the popup window name the new file as “ToDoRoomDatabase”.
The Room database has to be annotated with @Database. After the brackets, we can determine the entities, which is in our case the ToDo::class, and the version of the database.
When you want later on to modify the schema of the database, then you need to update the version number and define a migration strategy.
The Room database class has to be abstract and extended by RoomDatabase.
Now, the ToDoRoomDatabase::class should look like below.
We can reach DAO through the ToDoRoomDatabase::class. It will be an abstract function. So, paste into the body of the class the below line.
abstract fun toDoDao(): ToDoDao
Next, we are going to define a singleton ToDoRoomDatabase. It is necessery to avoid the multiple open instances of the database at the same time. It means, that we are going to define the companion object, and inside of it a nullable instance about the ToDoRoomDatabase::class.
Theafter, we will define a function, called getDatabase(), which will return the singleton instance. This method will create the database the first time when it is accessed. For this, we are going to use the database builder of Room to create a RoomDatabase object in the application context from the ToDoRoomDatabase::class. Here, we are going to name the database as well, which will be “todo_database”.
So, finally the ToDoRoomDatabase::class looks like below.
Step 4 – Implementation of the repository
The repository will be the access point to the data sources, which is in our case the Data Access Object. This class will be a clean API in our application.
The repository manages the queries and in case, if you have multiple backends, then you can access them here. In practice, the repository contains the logic for deciding whether to fetch data from a network or use results cached in a local database.
Now, create a new file inside of the repository package with the right mouse button, select New, then the Kotlin file/class option. In the popup window name the new file as “ToDoRepository”.
Paste there the below code.
Note that the DAO is passed as a constructor into the repository. Because of this, we can access the CRUD (Create, Read, Update, Delete) methods for the database.
We will get the list of the ToDos as a public LiveData property. Room will do the queries in a separate thread and the user interface will be notified because of the observer there. It means in our case, thet the RecyclerView will be populated by the previously created ToDos. We are going to talk about this later.
The source code is available on GitHub
I hope the description was understandable and clear. But, if you have still questions, then leave me comments below! 😉
Have a nice a day! 🙂