# Using Android RoomDatabase

The Room library is used to harness the full power of SQLite by providing an abstract layer over the SQLite. The library helps create a cache of your apps data on the device that your app is running on. This cached data allows users to see consistent copy of information regardless of whether there is internet connection or not.
This library contains three major components

- **Database**  - Serves as the main access point to the underlying connection to your app's data.

- **Entity**  - Represents the table in the database

- **Dao**  - Contains the abstract methods used to access the database.





To use the library , first add these dependencies to the `build.gradle` file inside the Dependencies block

```
dependencies{
    def room_version = "2.2.5"
     //Room
    implementation "androidx.room:room-runtime:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
}
``` 

## Creating an Entity
Entity defines a set of fields . Entities basically represents a table in the associated database to hold data items. 

```
    @Entity
    data class Note(
    @PrimaryKey(autoGenerate=true)
    val id:Int,
    val title:String,
    val note:String
)
``` 
 `@Entity` annotation shows that the class is a table in the database. By default Room uses the class name as the table name, but you can set a different name by using the `tableName` property, i.e `@Entity(tableName="table_name")`.The `@PrimaryKey(autoGenerate=true)` annotation declares the note `id` as the primary key and the `autoGenerate=true` tells us that the `id` is automatically generated.  The `id` , `title` and the `note` are column names but can be changed to different names by using `@ColumnInfo(name="column_name")`

## Dao
The data access objects include methods that offer abstract access the app's database. The DAOs help separate the different components of the database architecture.

```
@Dao
interface NoteDao {
    @Insert
    fun addNote(note: Note)
    @Query("SELECT * FROM note ORDER by id DESC")
     fun getAllNotes():List<Note>
    @Insert
    fun addMultipleNotes(vararg note: Note)
    @Update
     fun updateNote(note: Note)
    @Delete
    fun deleteNote(note: Note)
}
``` 
The `@Insert` annotation does exactly as it states. It creates an implementation that inserts all parameters to the database. `@Update` modifies a database entity, the `@Delete` removes an entity passed as a parameter and `@Query` loads all data from the app's database e.g `@Query("SELECT * FROM note ORDER by id DESC")`. This query returns a list of notes from the database and orders them by id in a descending order.

## Creating the Database
A database class should use the `@Database` annotation to mark the class as a RoomDatabase.  Inside this annotation we define all the entities and the  database version. In our case we only have one entity. A database class should be abstract and extend RoomDatabase. To change the database schema create the migration class and change the version number. In this post however, we wont do that.

```
@Database(entities = [Note::class], version = 1)
abstract class NoteDatabase:RoomDatabase() {
    abstract fun getNoteDao():NoteDao
    companion object{
        @Volatile private var instance : NoteDatabase? = null
        private val LOCK = Any()
        operator fun invoke(context: Context) = instance?: synchronized(LOCK){
             instance?: buildDatabase(context).also {
                 instance=it
             }
        }
        private fun buildDatabase(context: Context) = Room.databaseBuilder(
            context.applicationContext,
            NoteDatabase::class.java,
            "notedatabase"
        ).build()
    }
}
``` 
The abstract function `getNoteDao`  returns the `NoteDao`  which gives access to the Entity. Inside the `companion object` we build the database. we create an instance of the database and annotate it with `@Volatile` to make it available to all the threads. The `invoke` function checks if the instance is null. If it is not null we return the instance immediately. If it is null we again check in the synchronized block.  If inside the synchronized block the instance is null, we call the `buildDatabase` function to build our database.











