[Dev Log] Getting Started with Room Database

Skele·2024년 5월 1일

DevLog

목록 보기
1/4

Dependency


build.gradle ( project level )

keep in mind that ksp version has to match kotlin version
ksp 버전이 kotlin 버전과 맞아야 한다

plugins {
    ...
    // ksp plugin for room support
    id("com.google.devtools.ksp") version "1.9.22-1.0.17" apply false
}

build.gradle ( module level )

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    // room support
    id ("com.google.devtools.ksp")
}
...
dependencies {
	...
    // room
    implementation ("androidx.room:room-runtime:2.6.1")
    annotationProcessor("androidx.room:room-compiler-processing:2.6.1")
    implementation ("androidx.room:room-ktx:2.6.1")
    ksp("androidx.room:room-compiler:2.6.1")
}

Entity


/**
 * ### Entity
 * Entity represents table in Room database
 * - Entity class must have at least one PrimaryKey field ( autoGenerate equals autoIncrement in SQL )
 * - Room uses field name as column name as default, but can be changed with #ColumnInfo()
 * - Table and column name in database are case-insensitive
 * 
 * 데이터베이스에서 테이블을 표현하는 Entity.
 * - Entity는 하나의 PrimaryKey를 가져야한다.
 * - 기본적으로 field의 이름을 칼럼 이름으로 사용하지만, #ColumnInfo을 통해 변경할 수 있다.
 * - 테이블과 칼럼 이름은 대소문자를 구분하지 않는다.
 */
@Entity(tableName = "memo")
data class Memo(
    // Use `@ColumnInfo(name = "column name")` to change column name in database.
    // `@Ignore` annotation will exclude that field on column creation and will not persist.
    @PrimaryKey(autoGenerate = true) var id : Long = 0,
    val title : String,
    val content : String,
    val regDate : Long
){
    // When autoGenerate is set to true on primary key,
    // insert method treats 0 or null as 'not-set' while inserting the item.
    constructor(title: String, body: String, regDate: Long) : this(0, title, body, regDate)
}

Dao


/**
 * ### Dao
 * Data access object for specific entity.
 * - Dao is declared as an interface, and the framework generates its implementation.
 *
 * Entity 테이블에 접근하기 위한 Dao.
 * - Dao는 인터페이스로 선언되며 구현체는 프레임워크에 의해 생성된다.
 */
@Dao
interface MemoDao {
    @Query("SELECT id, title, content, regDate FROM memo WHERE id = (:id)")
    suspend fun get(id : Long) : Memo
    @Query("SELECT id, title, content, regDate FROM memo")
    suspend fun getAll() : List<Memo>
    @Insert(onConflict = OnConflictStrategy.ABORT)
    suspend fun insert(item : Memo) : Long
    @Insert(onConflict = OnConflictStrategy.ABORT)
    suspend fun insertAll(items : List<Memo>) : List<Long>
    @Update
    suspend fun update(item : Memo)
    @Delete
    suspend fun delete(item : Memo)
    @Query("DELETE FROM memo WHERE id = (:id)")
    suspend fun delete(id : Long)
}

Database


/**
 * ### RoomDatabase
 * Database created by android room framework.
 *
 * - In order to work properly, it has to declared as an abstract class.
 * - An Implementation of this abstract class is generated by the framework.
 * - Acquire generated database via #Room.databaseBuilder
 * - Each entity passed becomes a table in the sqlite database.
 *
 * Room 프레임워크에 의해 만들어지는 데이터베이스.
 *
 * - 추상 클래스로 선언되어야하며, 해당 구현체는 프레임워크에 의해 생성된다.
 * - 생성된 구현체는 #Room.databaseBuilder를 통해 사용할 수 있다.
 * - Entity로 선언된 데이터 클래스가 데이터베이스에 테이블로서 생성된다.
 *
 * @see RoomDatabase
 */
@Database(entities = [Memo::class], version = 1)
abstract class MemoDatabase : RoomDatabase() {

    abstract fun memoDao() : MemoDao

}

Repository


Repository must be initialized by calling initialize(context) before use.
There are many ways to do this, but to do it surely, I initialized the database on onCreate of Application using an Application class.

리포지토리는 initialize(context)를 통해 사전에 초기화 되어야한다.
초기화하는 시점은 다양할 수 있지만, 확실하게 하기 위해 어플리케이션이 시작될 때 초기화 되도록 Application class의 onCreate에서 초기화를 했다.

/**
 * ### Database Repository
 * A singleton class wrapping the database.
 * - Database is accessed through the repository.
 * - Data can be fetched from a database in the repository, or from network if necessary.
 *
 * 데이터 접근을 위한 Repository
 * - Repository를 통해 데이터에 접근.
 * - 데이터를 어디에서 가져오는 경로를 필요에 따라 데이터베이스와 네트워크 중에서 선택할 수 있다.
 */
class MemoRepository private constructor(context : Context){
    private val database : MemoDatabase = Room.databaseBuilder(
        context.applicationContext,
        MemoDatabase::class.java,
        "memo.db"
    ).build()

    private val memoDao = database.memoDao()

    suspend fun getAllMemos() : List<Memo>{
        return memoDao.getAll()
    }
    suspend fun getMemo(id : Long) : Memo{
        return memoDao.get(id)
    }
    suspend fun insertMemo(item : Memo) : Long{
        return memoDao.insert(item)
    }
    suspend fun updateMemo(item : Memo){
        memoDao.update(item)
    }
    suspend fun delete(item : Memo){
        memoDao.delete(item)
    }
    suspend fun delete(id : Long){
        memoDao.delete(id)
    }

    companion object{
        private var _instance : MemoRepository? = null
        val instance get() = _instance!!
        fun initialize(context : Context){
            if(_instance == null) _instance = MemoRepository(context)
        }
    }
}

Application class


class ApplicationClass : Application() {
    override fun onCreate() {
        super.onCreate()
        MemoRepository.initialize(this)
    }
}
profile
Tireless And Restless Debugging In Source : TARDIS

0개의 댓글