In the database the best practice to put your database access into certain interfaces. We want to get rid of the SQLite boilerplate free code. Room Write boilerplate code for you.You define the interfaces Room provide the implementation.
Compile time validation
The room is going to give you an error at compile time.So it goes out and verifies your query against the schema you have defined.
Data Changes
LiveData gets notified when the data changes.Because it Knows your query, it knows what things affect it.So it can let you know if that query changes. This is the part where all these architecture components work well together. Your ViewModel all you would write is the data, from the data is call this query and this all it will do.Whenever that data changes, your UI will get a new update.
Adding Components to your Project
open the build.gradle
file of project and add the line as shown below:
buildscript { repositories { maven { url 'https://maven.google.com' } jcenter() } }
Open the build.gradle file for your app and add the artifacts that you need as dependencies:
dependencies { ... implementation "android.arch.persistence.room:runtime:1.0.0" annotationProcessor "android.arch.persistence.room:compiler:1.0.0" implementation "android.arch.lifecycle:extensions:1.0.0" }
Create Entity
Represents a class that holds a database row. For each entity, a database table is created to hold the items. You must reference the entity class in the Database
class. Each field of the entity is persisted in the database unless you annotate it with @Ignore
. When a class is annotated with
@Entity
and is referenced in the entities
property of a @Database
annotation, Room creates a database table for that entity in the database.
@Entity public class User { @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "user_id") public long userId; @ColumnInfo(name = "first_name") public String firstName; @ColumnInfo(name = "created_date") public Date createDate; @Ignore public int age; }
Nested objects
You’d like to express a POJO as a cohesive whole in your database logic.In these situations, you can use the @Embedded
annotation to represent an object that you’d like to decompose into its subfields within a table. You can then query the embedded fields just as you would for other individual columns. Our User
class can include a field of type Address
. To store the composed columns separately in the table, include an Address
field in the User
class that is annotated with @Embedded
, as shown in the following code snippet:
public class Address { private String street; private String city; private String state; @ColumnInfo(name = "post_code") private String postCode; ... } @Entity public class User { ... @Embedded public Address address; }
Indices and uniqueness
Index certain fields in the database to speed up your queries. To add indices to an entity, include the indices
property within the @Entity
annotation.You can enforce this uniqueness property by setting the unique
property of an @Index
annotation to true
.
@Entity(indices = {@Index(value = {"first_name", "last_name"}, unique = true)}) class User { @PrimaryKey public int id; .... }
Relationships
Room allows you to define Foreign Key constraints between entities. For example, if there’s another entity called Book
, you can define its relationship to the User
entity using the @ForeignKey
annotation, as shown in the following code snippet:
@Entity(foreignKeys = @ForeignKey(onDelete = CASCADE, entity = User.class, parentColumns = "user_id", childColumns = "user_id")) public class Book { @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "book_id") private int bookId; private String title; @ColumnInfo(name = "user_id") private long userId; .... }
You can tell SQLite to delete all books for a user if the corresponding instance of User
is deleted by including onDelete=CASCADE
in the @ForeignKey
annotation.
Data Access Objects (DAO)
This component represents a class or interface as a Data Access Object (DAO). DAO are responsible for defining the methods that access the database. When generating the code at compile time, Room creates an implementation of this class.
@Insert
Create a DAO method annotate with @Insert
.Room generates an implementation that inserts all parameters into the database in a single transaction. The following code snippet shows example queries:
@Dao public interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) void insertAll(List<User> user); ... }
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>
.
@Update
It uses a query that matches against the primary key of each entity.
@Update public void updateUsers(User... users);
@Delete
Deletes a set of entities, given as parameters, from the database. It uses the primary keys to find the entities to delete.
@Delete public void deleteUsers(User... users);
Delete and Update method can return an int
value instead, indicating the number of rows updated in the database.
@Query
It allows you to perform read/write operations on a database. Each @Query
method is verified at compile time.
The 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.
@Dao public interface UserDao { ... //:id bind parameter with the id @Query("delete from user where user_id=:id") int deleteUser(int id); @Query("select * from user") LiveData<List<User>> fetchAllUser(); @Query("update user set street=:street where state in(:state)") long updateAddressByState(String[] state, String street); }
Querying multiple tables(JOIN)
The room allows you to write 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.
@Dao public interface BookDao { @Query("SELECT user.*,count(book.user_id) as borrowe FROM user LEFT JOIN book ON user.user_id = book.user_id group by user.user_id,book.user_id") LiveData<List<UserBooks>> fetchBookBorrower(); }
Data type converters
You sometimes use a custom data type whose value you would like to store in the database in a single column. To add this kind of support for custom types, you provide a TypeConverter
, which converts a custom class to and from a known type that Room can persist.
public class Converters { @TypeConverter public static Date fromTimestamp(Long value) { return value == null ? null : new Date(value); } @TypeConverter public static Long dateToTimestamp(Date date) { return date == null ? null : date.getTime(); } }
Create Database
The annotation defines the list of entities, and the class’s content defines the list of data access objects (DAOs) in the database. It is also the main access point for the underlying connection.
The annotated class should be an abstract class that extends RoomDatabase
.
@Database(version = 1, entities = {User.class, Book.class}) @TypeConverters({Converter.class}) abstract class AppDatabase extends RoomDatabase() { // BookDao is a class annotated with @Dao. abstract public BookDao bookDao(); // UserDao is a class annotated with @Dao. abstract public UserDao userDao(); // UserBookDao is a class annotated with @Dao. abstract public UserBookDao userBookDao(); }
The class must contain an abstract method that has zero arguments and returns the class that is annotated with @Dao
.
appDatabase = Room.databaseBuilder(context, AppDatabase.class, AppDatabase.DATABASE_NAME).build();
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long periods of time.
At runtime, you can acquire an instance of it by calling Room.databaseBuilder()
or Room.inMemoryDatabaseBuilder()
.
public void insertUser() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... voids) { appDatabase.userDao().insertAll(databaseCreator.getRandomUserList()); return null; } }.execute(); }
Download this project from GitHub.