안드로이드) Room (1)

밍나·2022년 6월 2일
0

Android

목록 보기
35/36

✏️ Room

1. Room

  • 안드로이드 앱에서 로컬 DB를 사용해야 할 때 이전에는 SQLite를 사용했다.
  • Room은 코드 작성을 편하게 하기 위해 SQLite를 추상화한 라이브러리로 내부적으로는 SQLite 이용하고 있어 함수에 정보만 주면 쉽게 로컬 DB를 사용할 수 있다.

2. Room의 구성 요소

  • Room은 database, entity, DAO 3가지로 구성되어 있다.
  • 앱은 Room 데이터베이스를 사용해 DAO를 가져온다. DAO를 사용해 데이터베이스에서 엔티티를 가져오고, 해당 엔티티에 대한 변경 내용을 데이터베이스에 저장한다.
  • 앱은 엔티티를 사용해 데이터베이스 내 테이블 컬럼에 해당하는 값을 가져오고 설정한다.

(1) database

  • 애플리케이션에서 영구적, 관계형 데이터에 대한 기본 연결을 위한 주요 진입점을 제공하며, 데이터베이스 홀더를 포함한다.
  • 데이터베이스 클래스를 만드는 조건은 다음과 같다.
    • RoomDatabase를 상속한 추상 클래스에 @Database 애노테이션을 추가한다.
    • 데이터베이스에 포함할 엔티티의 목록을 애노테이션 내에 포함해야 한다.
    • 매개 변수를 갖지 않고, @Dao 클래스를 반환하는 추상 메서드를 포함한다.
  • 런타임에 Room.databaseBuilder() 또는 Room.inMemoryDatabaseBuilder() 호출을 통해 Database 인스턴스를 얻을 수 있다.

(2) entity

  • 데이터베이스의 테이블을 표현한다.
  • POJO 클래스에 @Entity 애노테이션을 추가하는 것으로 엔티티 클래스를 생성하고 이를 @Database 애노테이션에 추가할 수 있다.

(3) DAO(Data Access Object)

  • @Dao 애노테이션을 인터페이스에 사용하며, 데이터베이스에 접근하려고 사용되는 추상 메서드를 포함한다.

✏️ Room Database 사용 방법

1. dependency 설정

plugins {
   ...
   id 'kotlin-kapt'
}

...

dependencies {
    def room_version = "최신 버전"
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
    implementation "androidx.room:room-rxjava2:$room_version"
    implementation "androidx.room:room-guava:$room_version"
    implementation "androidx.room:room-testing:$room_version"
    ...
}

2. 컴파일러 옵션 설정

  • Room은 다음과 같은 애노테이션 프로세서 옵션을 갖는다.
  • room.schemaLocation : 데이터베이스 스키마를 JSON 파일 형태로 추출하고 이를 저장할 디렉터리를 설정한다.
  • room.incremental : gradle에서 증분 애노테이션 프로세서를 활성화한다.
  • room.expandProjection : 이 옵션을 활성화하면, DAO 클래스 내 메서드에서 스타(*) 프로젝션 사용시 메서드 반환 타입을 가진 필드만 포함하도록 쿼리를 작성한다.
android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [
                    "room.schemaLocation":"$projectDir/schemas".toString(),
                    "room.incremental":"true",
                    "room.expandProjection":"true"]
            }
        }
    }
}

✏️ Database Entity 생성

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "user_table", ignoredColumns = ["age"])
data class User (
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0, // 고유 ID값
    @ColumnInfo(name = "first_name")
    var firstName: String = "",
    @ColumnInfo(name = "last_name")
    var lastName: String = "",
    var age: String = ""
)
  • 코틀린에서는 data class를 사용하여 getter/setter를 따로 구현할 필요가 없다.

(1) Entity 애노테이션

  • @Entity 애노테이션을 클래스에 붙이고, 필드를 선언해 엔티티를 정의할 수 있다.
  • 데이터베이스의 entities로 추가된 엔티티 클래스는 데이터베이스 인스턴스가 생성될 때 테이블로 생성된다.

(2) 테이블 이름

  • 기본적으로 Room에서는 엔티티 클래스 이름을 테이블 이름으로 사용한다. 만약 이름을 설정하고 싶다면 @Entity의 tableName 속성에 값을 설정한다.

(3) 기본키

  • 기본키에는 @PrimaryKey 어노테이션을 붙인다.
  • 기본키를 고유 ID 값으로 지정해 데이터가 생성될 때마다 자동으로 고유 ID 값이 1씩 증가하면서 생성될 수 있도록 (autoGenerate=true)로 지정한다.

(4) 컬럼명

  • 테이블 내 컬럼의 이름도 클래스의 필드의 이름으로 사용된다. 만약 컬럼 이름을 설정하고 싶다면 @ColumnInfo 애노테이션을 필드에 추가한다.

(5) 필드 무시

  • 엔티티의 필드를 테이블의 컬럼으로 만들고 싶지 않다면, 필드에 @Ignore을 붙이면 된다.
  • 하지만 위의 방법보다 @Entity 속성인 ignoredColumns에 필드명을 추가하는 것을 권장한다.

✏️ 관계 설정

1. 관계 설정

  • SQLite는 관계형 데이터베이스로 객체 간 관계를 지정할 수 있다.
  • 관계형 매핑 라이브러리에서 엔티티 객체가 서로를 참조하는 것을 허용하지만 Room은 이를 명시적으로 금지한다.
  • 직접적으로 관계를 맺을수는 없지만, Room은 엔티티간에 외부키를 정의하는것을 허용하고 있다.

2. 일 대 다 관계 설정

  • 아래는 Book 엔티티가 @ForeignKey 애노테이션을 사용해 User 엔티티와 관계를 정의한 것이다.
@Entity(
    foreignKeys = [
        ForeignKey(
            entity = User::class,
            parentColumns = ["id"],
            childColumns = ["user_id"])
    ]
)

data class Book (
    @PrimaryKey
    var bookId: Int = 0,

    var title: String = "",

    @ColumnInfo(name = "user_id")
    var userId: String = ""
)
  • user_id 외래키를 통해 0개 이상의 Book 인스턴스가 하나의 User 인스턴스에 연결될 수 있으므로 User와 Book 사이의 일 대 다 관계를 모델링한다.
  • 외래키는 참조된 엔티티가 변경될 때 특정 작업을 수행할 수 있다.

3. 다 대 다 관계 설정

  • 다 대 다 관계는 각 엔티티가 0개 이상의 다른 인스턴스에 연결될 수 있다.
  • 예를 들어 음악 스트리밍 앱에서 각 재생 목록에는 여러 개의 노래가 있을 수 있으며, 각 노래는 여러 재생 목록에 포함될 수 있다. 이 예제에서 다 대 다 관계를 모델링하려면 3가지 객체를 만들어야 한다.
    • 재생 목록(Playlist) 엔티티 클래스
    • 노래(Song) 엔티티 클래스
    • 각 재생 목록에 있는 노래에 대한 정보를 담는 클래스(PlaylistSongJoin)]
@Entity
data class Playlist(
    @PrimaryKey
    val id: Int,
    val name: String
)

@Entity
data class Song(
    @PrimaryKey
    val id: Int,
    val songName: String,
    val artistName: String
)

@Entity(
    tableName = "playlist_song_join",
    primaryKeys = ["playlistId", "songId"],
    foreignKeys = [
        ForeignKey(entity = Playlist::class,
            parentColumns = ["id"],
            childColumns = ["playlistId"]),
        ForeignKey(entity = Song::class, 
            parentColumns = ["id"], 
            childColumns = ["songId"])]
)
data class PlaylistSongJoin (
    val playlistId : Int,
    val songId : Int
)
  • 독립적인 단위로 엔티티 클래스를 정의한 다음, 재생 목록에 있는 노래에 대한 정보를 담을 중간 클래스를 외래키 참조가 포함된 엔티티로 정의한다.
profile
🤗🤗🤗

0개의 댓글