본문 바로가기

[Android/Kotlin] 안드로이드 Room Database 사용하기(3) Migration

꿈꾸는블로그왕 2021. 2. 5.

 

안녕하세요. 오늘은 Room Database를 사용하다가 Migration이 필요할 때  Migration 하는 방법에 대해서 알아보겠습니다. 테이블을 추가하거나 컬럼을 변경하는 경우에 유용하게 사용할 수 있습니다.

 

오늘 설명드릴 케이스는 expense_table에 새로운 컬럼을 추가하는 방법입니다.

(지출 목록을 분류할 수 있는 category 컬럼 추가 예정)

 

지난 예제에 이어서 설명드리겠습니다.

 

2021/02/01 - [Android/AAC] - [Android/Kotlin] 안드로이드 Room Database 사용하기(2) Select...

2021/01/30 - [Android/AAC] - [Android/Kotlin] 안드로이드 Room Database 사용하기(1)

 

먼저 그냥 컬럼을 추가한다고 생각하고 데이터 모델에 category를 추가해 줍니다.

@Entity(
    tableName = "expense_table"
)
data class Expense(
    var amount: Int? = 0,
    var title: String? = "",
    var description: String? = "",
    @ColumnInfo(name = "reg_date")
    var regDate: Date = Date(),
    // 신규 추가 컬럼
    var category: Int? = 0
) {
    @PrimaryKey(autoGenerate = true)
    var id: Int? = null
}

그리고 나서 실행을 해주면... 에러 발생!

 

데이터베이스 스키마에 변화가 생겼을 때 그대로 실행하면 아래와 같은 에러가 발생합니다. 

Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.

 

[Error  Message]

Dabasebase version 동일하다는 에러입니다.

version을 2로 올리고 실행해 봅니다.

이번에는 migration을 찾을 수 없다는 에러 메세지가 또 나타납니다.

마이그레이션만 추가하면 이제 테이블의 컬럼을 추가할 수 있습니다!

 

마이그레이션 하는 방법은 아래와 같습니다.

STEP01. 데이터베이스 버젼 업

ExpenseDatabase파일의 Database version을 2로 수정합니다.

 

STEP02. 마이그레이션 코드 작성

이제 테이블 변경 쿼리를 작성해 줍니다.

// Migration 코드
private val MIGRATION_1_2 = object : Migration(1, 2) {
	override fun migrate(database: SupportSQLiteDatabase) {
		database.execSQL("ALTER TABLE 'expense_table' ADD COLUMN 'category' INTEGER")
	}
}

 

STEP03. 마이그레이션 추가하기

작성한 마이그레이션 코드를 addMigrations에 추가해줍니다. 해당 메소드는 데이터베이스 빌드전에 호출해줍니다.

.addMigrations(MIGRATION_1_2)

[ExpenseDatabase.kt]

@Database(
    entities = [Expense::class],
    // version -> 2
    version = 2,
    exportSchema = false
)
@TypeConverters(Converters::class)
abstract class ExpenseDatabase : RoomDatabase() {

    abstract fun expenseDao(): ExpenseDao

    companion object {
        @Volatile
        private var INSTANCE: ExpenseDatabase? = null

        fun getDatabase(context: Context): ExpenseDatabase {
            val tempInstance = INSTANCE
            if (tempInstance != null) return tempInstance
            synchronized(this)  {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    ExpenseDatabase::class.java,
                    "expense_database")
                // addMigrations 추가
                .addMigrations(MIGRATION_1_2)
                .build()
                INSTANCE = instance
                return instance
            }
        }

		// Migration 코드
        private val MIGRATION_1_2 = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE 'expense_table' ADD COLUMN 'category' INTEGER")
            }

        }
    }

}

 

STEP04. 실행하기

새로운 데이터를 입력 및 저장합니다.

Database Inspector화면에서 category 컬럼이 생기고 default값인 0이 추가되었습니다.

하지만 기존의 데이터 값에 Null 표시가 됩니다....

마이그레이션 당시 Default값을 넣기 위해 Default 0 이라는 쿼리를 추가해줍니다.

private val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE 'expense_table' ADD COLUMN 'category' INTEGER DEFAULT 0")
    }

}

 

그럼 이제 다시 시도해 봅니다.

 

테스트를 위해 기존 데이터베이스를 삭제하고 다시 반복했습니다.

category에 default 값이 0 들어간걸 확인할 수 있습니다.

댓글