Room Persistence Library
구글에서 제공하는 ORM
기기에 데이터를 저장하고자 할 때 사용
구성 요소
덧, 그 전에 용어 정리
Object Relational Mapping
객체 - 관계 매핑
이미지 출처: https://www.nextree.co.kr/p5864/
보통 ORM에서는 Entity가 서로를 참조할 수 있지만 Room은 명시적으로 금지하고 있다.
왜냐하면 클라이언트 단위의 데이터베이스이기 때문에 개체를 참조한다면 쿼리 처리에 오랜 시간이 걸리고 결과적으로 UI 스레드의 성능에 지장을 줄 수 있기 때문이다.
이런 이유로 개체 참조가 아니라 Entity간의 관계를 정의하는 형태로 사용해야한다.
예시 코드
@Entity
data class Character (
@PrimaryKey @ColumnInfo(name = "character_id") val characterId: Int,
@ColumnInfo(name = "place_belong_id") val placeBelongId: Int,
@ColumnInfo(name = "character_name") val characterName: String
)
data class PlaceWithCharacter(
@Embedded val place: Place,
@Relation(
parentColumn = "placeId",
entityColumn = "placeBelongId"
)
val characters: List<Character>
)
출처: https://dunchi.tistory.com/94 [둔치의 개발이야기]
위 코드는 place
와 characters:List<Character>
속성을 가지므로 palce와 character가 1:n 매핑이다.
만약 place
와 character: Character
였으면 1:1 매핑이었겠지.
더 정확하고 자세한건 안드로이드 공식문서를 참고하자
위와 같은 이유로
Room은 Primitive Type과 Boxed Type(원시 자료형의 Wrapper Class)을 변환하는 기능은 제공하지만 항목 간 개체 참조는 허용하지 않는다.
(Room provides functionality for converting between primitive and boxed types but doesn't allow for object references between entities.)
때문에 사용자가 정의한 data type의 값을 단일 데이터베이스의 column에 저장하려고 할 때 TypeConverter를 사용해야 한다.
TypeConverter를 통해 Room에서 처리할 수 있는 데이터 타입으로 상호변환할 수 있다.
아래 코드는 Date
인스턴스를 유지하려는 상황이다.
아래와 같이 TypeConverter를 작성하여 데이터베이스에 동등한 Unix 타임스탬프를 저장할 수 있다.
class Converters {
@TypeConverter
fun fromTimestamp(value: Long?): Date? {
return value?.let { Date(it) }
}
@TypeConverter
fun dateToTimestamp(date: Date?): Long? {
return date?.time?.toLong()
}
}
출처: https://developer.android.com/training/data-storage/room/referencing-data [Room을 사용하여 복잡한 데이터 참조]
뽀모도로 어플 프로젝트를 진행하다 빌드 에러가 났다.
error: Cannot figure out how to save tags field into database. You can consider adding a type converter for it.
Entity 역할을 하는 Data Class에 tags: ArrayList<String>
변수가 있었는데 이걸 처리하는 과정에서 발생한 오류였다.
아래와 같이 List을 Gson으로 변환하는 Converter를 만들어서 에러를 해결했다.
class Converters {
@TypeConverter
fun listToJson(value: List<String>?) = Gson().toJson(value)
@TypeConverter
fun jsonToList(value: String) = Gson().fromJson(value, Array<String>::class.java).toList()
}