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 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
* 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)
}
/**
* ### 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 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)
}
}
}
class ApplicationClass : Application() {
override fun onCreate() {
super.onCreate()
MemoRepository.initialize(this)
}
}