Android/note

[Android] Room Database 버전 올리기 그런데 오류를 곁들인 .. (Migration didn't properly handle)

김 안개 2023. 9. 15. 16:33

버전 관련해서 포스팅했는데 버전을 또 올려?!?!

 

[ 버전 업그레이드 하는 이유 ]

처음에 하나의 테이블(주제)을 만들고 기능을 추가하다보니 또 하나의 테이블(생각)을 만들고 ..

그러다보니 테이블간에 외래 키를 설정해주었어야 하는데 그걸 안해줘서 ..

초기화를 하려고하면 주제 삭제 -> 생각 삭제 -> 코멘트 삭제(또 추가된 테이블) 이렇게 플로우가 되는 것임 ..

일단 주제 삭제 -> 생각 삭제를 진행하면서는 외래 키를 생각해내지 못해서 코드로 작성했었다.

 

    override fun deleteAllTopic() {
        CoroutineScope(Dispatchers.IO).launch {
            var topicListCount = 0
            var thinkListCount = 0
            topicRepository.getTopicListCount()
                .catch { exception ->
                    printError("topicRepository.getTopicListCount()", exception.localizedMessage)
                }
                .collect {
                    topicListCount = it
                }
            thinkRepository.getThinkListCount()
                .catch { exception ->
                    printError("thinkRepository.getThinkListCount()", exception.localizedMessage)
                }
                .collect {
                    thinkListCount = it
                }

            if (topicListCount == 0) {
                topicContractView.showError(R.string.tag_topic_list_empty.toString(), "등록된 주제가 없습니다.")
            } else {
                topicRepository.deleteAllTopic()
                    .catch { exception ->
                        printError("topicRepository.deleteAllTopic()", exception.localizedMessage)
                    }
                    .collect {
                        if (thinkListCount != 0) {
                            thinkRepository.deleteAllThink()
                                .catch { exception ->
                                    printError("thinkRepository.deleteAllThink()", exception.localizedMessage)
                                }
                                .collect ()
                        }
                        topicContractView.showEmptyTopicList()
                    }
            }
        }
    }

 

개발새발이지만 .. 어쨌든 주제를 삭제하면 생각을 삭제하는 동작이 돌아갔음

 

근데 코멘트 테이블을 추가하고나니 저 안에서 어떻게 .. 코멘트를 삭제하나 ... 싶었는데 불현듯 학부생때 데이터베이스 시간에 CASCADE 배운게 생각이 나서 설정해주어야 겠다! 싶었는데

네. SQLite 에서는 컬럼 수정을 통해서 외래 키 설정이 안됩니다.

 

출처 : https://www.sqlite.org/lang_altertable.html

 

Room 데이터베이스를 하려면 SQLite 를 써야하다보니 SQLite 사이트는 이젠 저절로 켜놓고 시작함 ..

아무튼 위 사진을 보면 ALTER TABLE 을 통해 수정할 수 있는 기능이 몇 개 있는데 RENAME , ADD , DROP 만 사용이 가능함

외래 키를 설정해주려면 ADD CONSTRAINT 를 사용해야하는데 ADD COLUMN 만 가능함 왜냐고요? ADD CONSTRAINT 가 없음. 안됨.

 

[ 해결 과정 ]

1) 현재 있는 테이블 모두 삭제

database.execSQL(
  """
    DROP TABLE topics
  """.trimIndent()
)

database.execSQL(
  """
    DROP TABLE thinks
  """.trimIndent()
)

database.execSQL(
  """
    DROP TABLE comments
  """.trimIndent()
)

 

2) 외래 키 설정을 한 3개의 테이블 생성

database.execSQL(
  """
    CREATE TABLE topics (
      id INTEGER PRIMARY KEY NOT NULL,
      topic TEXT NOT NULL,
      registDate TEXT NOT NULL,
      updateDate TEXT NOT NULL
      )
  """.trimIndent()
)

database.execSQL(
  """
    CREATE TABLE thinks (
      id INTEGER PRIMARY KEY NOT NULL,
      topicId INTEGER NOT NULL,
      think TEXT NOT NULL,
      registDate TEXT NOT NULL,
      updateDate TEXT NOT NULL,
      FOREIGN KEY (topicId) REFERENCES topics (id) ON DELETE CASCADE ON UPDATE CASCADE
    )
  """.trimIndent()
)

database.execSQL(
  """
    CREATE TABLE comments (
      id INTEGER PRIMARY KEY NOT NULL,
      thinkId INTEGER NOT NULL,
      comment TEXT NOT NULL,
      registDate TEXT NOT NULL,
      FOREIGN KEY (thinkId) REFERENCES thinks (id) ON DELETE CASCADE ON UPDATE CASCADE
    )
  """.trimIndent()
)

 

3) MIGRATION 적용

 

그런데 발생한 오류 ..

 

[ ERROR  발생 -> 해결 ]

Migration didn't properly handle: thinks(com.w36495.about.domain.entity.Think)

사실 지난번에도 발생했던 오류인데 그때는 """ query """ 이걸 적용했더니 해결이 되었다. 

이번에 해결하였더니 지난번에 오류가 발생했던 이유는 잘못 작성한 쿼리 였던 것 같다. """ query """ 이걸로 해결이 되었으니까!

 

그런데 이번엔 """ query """ 했는데도 해결이 안됨

근데 에러 메세지를 보니 Topic 에서 문제가 생긴게 아니고 Think 부터 문제가 생긴 것을 확인 ->  그럼 외래 키 설정일텐데?

 

1) 일단 작성한 쿼리랑 Entity 가 불일치하는지 확인

작성한 쿼리 확인

 

database.execSQL(
  """
    CREATE TABLE thinks (
      id INTEGER PRIMARY KEY NOT NULL,
      topicId INTEGER NOT NULL,
      think TEXT NOT NULL,
      registDate TEXT NOT NULL,
      updateDate TEXT NOT NULL,
      FOREIGN KEY (topicId) REFERENCES topics (id) ON DELETE CASCADE ON UPDATE CASCADE
    )
  """.trimIndent()
)

 

나의 Entity 도 확인

 

@Entity(tableName = "thinks")
data class Think(
    @PrimaryKey
    val id: Long = System.currentTimeMillis(),
    val topicId: Long,
    val think: String,
    val registDate: String,
    val updateDate: String
)

 

컬럼들 모두 쿼리랑 알맞게 작성함 (사실 잘못쓴게 있을까봐 하나하나 확인했다)

그럼 뭐가 문제지? 계속 같은 에러가 떴다.

 

이번에도 도움받은 스택오버플로우 .. MikeT 씨에게 감사인사드린다.

 

 

 

Room Database Migration: java.lang.IllegalStateException: Migration didn't properly handle <table_name>

I am trying to create a new table using Room Database. I followed the same principles that I used for the first table that I already have in my program, but when the time comes to run the app, I ge...

stackoverflow.com

 

컴파일을 돌린 후, 생긴 Database 관련 파일에서 쿼리를 확인해봐라!

내가 작성한 쿼리랑 일치하는지 확인해보자! 가보자고!

 

맥에서는 command + F9 를 하면 컴파일이 된다!

 

 

Android 로 설정한 후 java -> com -> local -> AppDatabase (설정한 파일명에 따라 다를듯) 를 보면 확인할 수 있다.

createAllTables() 를 확인하면 됨!

 

 

컴파일을 돌려서 확인해보니, 외래 키 설정에 대해서 하~~~~~~나도 안들어가있다.

쿼리로는 외래 키 설정을 해주었는데, 왜 제대로 쿼리가 작동하지 않았지? 싶었다.

 

onDelete/onUpdate 설정 전(왼쪽) / 설정 후(오른쪽)

 

Entity 클래스에도 ForeignKey 를 설정해주면 된다 ..

그런데 onDelete / onUpdate 에 대해서 NO_ACTION 이 기본값으로 설정되어있으므로, NO_ACTION 이 아닌 다른 값으로 설정하고싶다면 오른쪽처럼 onDelete와 onUpdate 를 설정해주자!

 

테이블 생성 쿼리로는 다른 테이블을 참조한다고 얘기해줬는데, 막상 Entity 에서는 누가 누굴 참조하는지에 대해 나와있지 않으니 핸들링할 수 없는 것 같았다. 

 

아무튼 모두 수정 후, 다시 컴파일해보면 원하는 대로 들어가있음을 확인할 수 있다!

 

[ 결론 ]

설계를 잘하자 .. 처음 시작할 때 설계를 잘하자 ..