본문 바로가기
Android

[Kotlin] 코틀린 Room Database 사용하기. CRUD

by bryan.oh 2023. 8. 24.
반응형

Android Kotlin
ROOM

 

build.gradle

아래 내용 추가

plugins {
    id 'kotlin-kapt'
}

dependencies {
    def room_version = "2.5.2"
    implementation "androidx.room:room-runtime:${room_version}"
    implementation "androidx.room:room-ktx:${room_version}"
    kapt "androidx.room:room-compiler:${room_version}"
}

sync_now 클릭

 

Entity (Table) data class 

Person.kt 데이터 클래스

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey

@Entity(tableName = "person")
data class Person (
    @PrimaryKey(autoGenerate = true)
    val id: Int?,
    @ColumnInfo(name = "user_name", index = true)
    val name: String,
    val mobile: String? = null,
    @ColumnInfo(name = "reg_date",)
    val regDate: String,
    @Ignore val checked: Boolean = false
)
  • @Entity 에 tableName 으로 테이블명 지정. 없으면 클래스명과 같음.
  • @PrimaryKey 기본키 설정. autoGenerate 는 키 값을 입력하지 않아도 자동으로 생성됨.
  • @ColumnInfo 의 name 으로 테이블 컬럼 명 지정.
    • name: 열의 이름을 지정합니다. 기본적으로 변수의 이름과 동일한 값이 사용됩니다. 그러나 데이터베이스 테이블의 열 이름을 직접 지정하려는 경우에 사용됩니다.
    • typeAffinity: 열의 데이터 타입을 지정합니다. 기본적으로 Room은 변수의 타입을 기반으로 적절한 데이터 타입을 선택합니다. 예를 들어 String 변수는 TEXT 데이터 타입으로 매핑됩니다.
    • collate: 열의 콜레이션(collation)을 지정합니다. 데이터 정렬 및 비교 방식을 결정합니다.
    • defaultValue: 열의 기본값을 지정합니다. 데이터를 삽입할 때 해당 열에 값이 제공되지 않은 경우 사용됩니다.
    • index: 열을 인덱스로 설정할 지 여부를 결정합니다. 인덱스를 사용하면 데이터베이스 검색 성능을 향상시킬 수 있습니다.

 

DAO 생성

PersonDao.kt 인터페이스

import androidx.lifecycle.LiveData
import androidx.room.*
import com.example.test01.models.Person

@Dao
interface PersonDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insert(person: Person)

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insert(person: List<Person>)
    
    @Update(onConflict = OnConflictStrategy.REPLACE)
    suspend fun update(person: Person)
    
    @Delete
    suspend fun delete(person: Person)
    
    @Query("SELECT * FROM person")
    fun getAll(): List<Person>

    @Query("SELECT * FROM person")
    fun getAllLive(): LiveData<List<Person>>
}
  • interface 로 생성하고 @Dao annotation 을 붙혀줍니다.
  • insert, update, delete 의 함수명은 아무거나 상관없습니다. insertPerson() 도 가능.
  • 단, @Insert, @Update 등 annotation 은 변경 불가
  • insert, update, delete 에  List parameter 입력 가능
  • LiveData 는 database 를 observe 하고 있음. db 의 데이터가 변경사항이 있을 시, LivaData 변수도 같이 변경됨.

 

TypeConverter 생성

타입 변환이 필요한 경우에만 생성

Entity 에 Date 타입 컬럼을 사용하기 때문에, 아래 Converters 가 필요.

import androidx.room.TypeConverter
import java.util.*

class Converters {
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }

    @TypeConverter
    fun dateToTimestamp(date: Date?): Long? {
        return date?.time
    }
}

 

 

Database : RoomDatabase() 생성

abstract

싱글톤으로 생성

@Database(
    entities = [Person::class],
    version = 1
)
@TypeConverters(Converters::class)
abstract class MyDatabase: RoomDatabase() {

    abstract fun getPersonDao(): PersonDao

    companion object {
        @Volatile
        private var instance: MyDatabase? = null

        private fun buildDatabase(context: Context): MyDatabase =
            Room.databaseBuilder(
                context.applicationContext,
                MyDatabase::class.java,
                "solbar_app.db"
            ).build()

        fun getInstance(context: Context): MyDatabase =
            instance ?: synchronized(this){
                instance ?: buildDatabase(context).also { instance = it }
            }
    }
}

 

Activity

// class property 로
lateinit var database: MyDatabase

// onCreate 안에서
database = MyDatabase.getInstance(this)

 

 

아래는 Activity 에서 버튼 클릭 했을 때 동작하면 됩니다.

 

Insert

val person = Person(name = "hello", regDate = Date())
val person2 = Person(name = "bryan", mobile="010-1111-0001", regDate = Date())

CoroutineScope(Dispatchers.IO).async {
    database.getPersonDao().insert(person)
    database.getPersonDao().insert(person2)
}

 

Select

CoroutineScope(Dispatchers.IO).async {
    val personList = database.getPersonDao().getAll()
    personList.forEach {
        println(it.toString())
    }
    runOnUiThread {
        binding.roomDisplayTextview.text = "건수 : ${personList.size}"
    }
}

Update

val person = Person(id= 1, name = "hello!!", mobile = "010-0000-0001", regDate = Date())
CoroutineScope(Dispatchers.IO).async {
    database.getPersonDao().update(person)
}

Delete

val person = Person(id=1, name="", regDate = Date())
CoroutineScope(Dispatchers.IO).async {
    database.getPersonDao().delete(person)
}

 

Select LiveData<T>

val personList = database.getPersonDao().getAllLive()
personList.observe(this) {
    it.forEachIndexed { index, person ->
        Log.d("From Database", "${index} : ${person}")
    }
}

 

 

728x90
반응형

댓글