Android/note

[Android] Room Database 마이그레이션 도오전

김 안개 2023. 8. 30. 18:27

2개의 테이블만 가지고 있던 나 ... 나의 조그만 데이터베이스 ..

그런데 1개의 테이블을 더 추가해야하는데 추가하려면 데이터베이스 마이그레이션을 해야한다고 한다!

그럼 레쯔고 ...!

 

 

참고한 사이트는 공식문서에 있는 Room 데이터베이스 이전 관련 내용

 

Room 데이터베이스 이전  |  Android 개발자  |  Android Developers

Room 라이브러리를 사용하여 데이터베이스를 안전하게 이전하는 방법 알아보기

developer.android.com

 

첫번째 시도 : 자동 이전


 

 

말이 자동이전 .. 너무 쉬울 것 같았고 추가해줘야 할 것들도 얼마 없었다

 

@Database(
  version = 2,
  entities = [User::class],
  autoMigrations = [
    AutoMigration (from = 1, to = 2)
  ]
)
abstract class AppDatabase : RoomDatabase() {
  ...
}

 

version 을 1 -> 2로 한 단계 올려주고, autoMigrations = [ ] 을 통해 버전만 명시해주면 되었음

물론 새로운 Entity 파일을 생성해서 @Entity 어노테이션도 달아주어야 함!

 

하지만 에러 나오죠? 뿜뿜 튀어나오죠? 자동이라더니 생각보다 쉽지않죠?

 

error: Schema export directory is not provided to the annotation processor so we cannot import the schema. To generate auto migrations, you must provide room.schemaLocation annotation processor argument AND set exportSchema to true.

 

1. app 수준의 build.gradle 에서 annotation processor argument 을 추가해주어야함

2. RoomDatabase() 를 상속받는 AppDatabase 의 @Database 어노테이션 내에서 exportSchema = true 해주어야 함

 

참고

 

 

Room - Schema export directory is not provided to the annotation processor so we cannot export the schema

I am using Android Database Component Room I've configured everything, but when I compile, Android Studio gives me this warning: Schema export directory is not provided to the annotation proces...

stackoverflow.com

 

아 ... 뭔가 이해가 안되어서 그냥 SQL 만 추가하면 되는 수동 이전을 시도해보기로함ㅠ

 

두번째 시도 : 수동 이전


 

@Database(
  version = 2,
  entities = [User::class, 추가될 class],
)
abstract class AppDatabase : RoomDatabase() {
	val MIGRATION_1_2 = object : Migration(1, 2) {
		override fun migrate(database: SupportSQLiteDatabase) {
			database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, `name` TEXT, " +
            "PRIMARY KEY(`id`))")
        }
	}

	val MIGRATION_2_3 = object : Migration(2, 3) {
  		override fun migrate(database: SupportSQLiteDatabase) {
    		database.execSQL("ALTER TABLE Book ADD COLUMN pub_year INTEGER")
  		}
	}

	Room.databaseBuilder(
    	applicationContext, 
        MyDb::class.java, 
        "database-name"
    )
  	.addMigrations(MIGRATION_1_2, MIGRATION_2_3)
    .build()
}

 

[1] entities 리스트에 새로 추가할 @Entity 가 달린 class 를 추가

[2] version 을 1에서 2로 up!

[3] MIGRATION_1_2 를 작성해준다

여기서 제일 고생했던 부분인데 .... 공식홈페이지에 나와있는 (위의 코드에서 보이는 CREATE TABLE 문법) 문법을 작성했는데 계속 Migration didn't properly handle 에 대한 에러가 나와서 정말 .. 짜증났다ㅠ

왜!!! 왜!!! 외 않돼는건대!!!!!

 

@Entity(tableName = "comments")
data class Comment(
    @PrimaryKey
    val id: Long,
    val thinkId: Long,
    val comment: String,
    val registDate: String,
)

 

이번에 새로 만든 Comment Entity 에 대한 테이블을 만들려고 했다. 분명.. 그랬다..

 

CREATE TABLE `comments` (
	`id` INTEGER,
	`thinkId` INTEGER,
	`comment` TEXT,
	`registDate` TEXT,
	PRIMARY KEY(`id`)
)

 

위와 같이 쿼리를 입력해준 후 addMigration(MIGRATION_1_2) 를 통해 추가해주었는데도 아까와 같은 에러가 또 나왔다.

Migration didn't properly handle Migration didn't properly handle Migration didn't properly handle Migration didn't properly handle Migration didn't properly handle Migration didn't properly handle Migration didn't properly handle Migration didn't properly handle Migration didn't properly handle Migration didn't properly handle Migration didn't properly handle 

어쩔티비다 정말 

 

그러다 Room 데이터베이스 이전 관련 내용이 있는 공식문서의 가장 하단에 Room 2.2.0 으로 업그레이드 시 열 기본값 처리에 대한 내용을 발견했다.

 

 

Room 데이터베이스 이전  |  Android 개발자  |  Android Developers

Room 라이브러리를 사용하여 데이터베이스를 안전하게 이전하는 방법 알아보기

developer.android.com

 

해당 내용은 Room 2.2.0 이상에서는 기본값을 정의해주어야 한다는 내용인데, 난 그 이전버전을 사용하지 않았어서 해당되지 않을 내용..

하지만!!! 하지만!!! 거기서 해결법을 찾아내었다면!!! 가장 하단의 코드 샘플에서 새롭게 작성된 코드를 발견 .. 

 

// Migration from 2 to 3, Room 2.2.0.
val MIGRATION_2_3 = object : Migration(2, 3) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("""
                CREATE TABLE new_Song (
                    id INTEGER PRIMARY KEY NOT NULL,
                    name TEXT,
                    tag TEXT NOT NULL DEFAULT ''
                )
                """.trimIndent())
        database.execSQL("""
                INSERT INTO new_Song (id, name, tag)
                SELECT id, name, tag FROM Song
                """.trimIndent())
        database.execSQL("DROP TABLE Song")
        database.execSQL("ALTER TABLE new_Song RENAME TO Song")
    }
}

 

""" 쿼리문 """ 과 같이 """ """ 사이에 그냥 일반적으로 쿼리를 짜듯 넣을 수 있는 문법(?)이다 ..

이걸로 하니까 마이그레이션 바로 됨........어이없네... 어제부터 꼬박 거의 하루~이틀을 씨름했는데 ...

 

근데 덕분에 Room 데이터베이스가 어떻게 생성되는지에 파헤쳐봤는데 JournalMode 를 TRUNCATE 로 설정해주어야 한다는 것도 알아냈음.. 소득있다..