본문 바로가기

안드로이드/코틀린

[Android/Kotlin] Room 마이그레이션

반응형

Entity(테이블)의 컬럼이 추가되거나, Entity 자체를 추가하는등 Database 수정이 발생했을때 아무런 조치를 취하지 않고 버전만 올린다면 저장되어 있던 데이터가 날아가 사용자에게 불편함을 줄 수 있어 필수로 처리 해줘야 합니다.  Room 사용법은 제 포스팅을 참고해주세요.

>> 버전업 

@Database(version = 2, entities = [PlantData.Item::class,DiaryData.Item::class])
abstract class DB : RoomDatabase() {

Room의 구성요소중 하나임 RoomDatabase에 명시된 버전을 수정합니다. [ ex) 1 -> 2 ] 

>> Migration 객체 생성 및 sql 문 작성 

        private var MIGRATION_1_2 = object : Migration(1,2){
            override fun migrate(database: SupportSQLiteDatabase) {

                database.execSQL("CREATE TABLE '${TodoData.TABLE_NAME}' ('id' INTEGER NOT NULL DEFAULT 0," +
                        "'type' TEXT NOT NULL, 'desc' TEXT NOT NULL, 'time' INTEGER NOT NULL DEFAULT 0," +
                        "'alarmTime' INTEGER NOT NULL DEFAULT 0, 'isComplete' INTEGER NOT NULL DEFAULT 0, " +
                        "'plantId' INTEGER NOT NULL DEFAULT 0, PRIMARY KEY('id'))")
            }
        }
        ...
        
        fun getInstance(context: Context): DB {
            return INSTANCE ?: synchronized(DB::class) {
                INSTANCE ?: Room.databaseBuilder(
                    context.applicationContext,
                    DB::class.java,
                    dbName
                ).addMigrations(MIGRATION_1_2)
                    .build().also { INSTANCE = it }
            }
        }

그리고 이전 버전과 업데이트할 버전에 맞는 Migration 객체를 생성해 업데이트 되는 부분에대한 sql문을 작성합니다. 그리고 Room 인스턴스 생성시 마이그레이션 객체를 넣어줍니다. 

주의사항

  • Entity 의 Long 타입으로 선언했어도 sql문에선 INTEGER로 작성해야 한다.
  • Entity의 Boolean 타입도 INTEGER로 작성해야 합니다.
  • NOT NULL과 NULL ABLE을 잘 구분해서 작성해야 합니다
  • default 값이 일치해야 합니다.
    • boolean 타입은 default값도 Integer 형태로 작성해야 합니다.
  • Entity 클래스 에서도 디폴트 값을 설정해줘야 합니다.

>> 디폴트값 설정

테이블을 추가하거나 컬럼을 추가할때 위에서 작성한 sql문의 디폴트 값과 생성한 테이블 컬럼의 디폴트 값이 일치해야 합니다. 일반적으로 변수에 값을 초기화 하면 추가되는 테이블과 일치하지 않다고 에러가 발생해 'columnInfo' 어노테이션을 이용해 디폴트 값을 설정해야 합니다. ( 밑의 코드를 예로 plantId = 0 이라고 명시해도 마이그레이션시 디폴트 값은 null이라고 뜨는걸 확인하실 수 있습니다. ) 

    @Entity(tableName = "todo")
    data class Item(
        @PrimaryKey(autoGenerate = true) var id: Long? = null,
        @ColumnInfo(defaultValue = "1")
        var type: Int,
        var desc: String = "",
        @ColumnInfo(defaultValue = "0")
        var time: Long ,
        @ColumnInfo(defaultValue = "0")
        var alarmTime: Long,
        @ColumnInfo(defaultValue = "0")
        var isComplete: Boolean = false,
        @ColumnInfo(defaultValue = "0")
        var plantId: Long)

 

>> 에러 확인 

마이그레이션이 실패 했을때 발생하는 에러 문구를 보면 기존에 작성한 Entity class와 마이그레이션시 작성된 sql정보가 일치 하지 않았을 경우 비교해보고 틀린 부분을 고쳐주면 됩니다. 위처럼 'Expected'와 'Found'  각 tableinfo의 값을 비교하시면 됩니다.

 

 

 

반응형