객체 모델 변경 - Kotlin SDK
개요
Realm 객체 모델 을 만든 후 객체 스키마를 변경할 수 있습니다. 스키마 변경 유형에 따라 변경 사항이 자동으로 적용되거나 새 스키마를 수동으로 업데이트해야 할 수 있습니다.
Realm 객체 모델에서 속성을 추가하거나 삭제할 때 Realm은 Realm 객체 스키마 를 자동으로 업데이트합니다. 스키마 버전만 업데이트하면 됩니다.
다른 모든 스키마 변경의 경우 지정된 객체의 이전 인스턴스를 새 스키마로 수동으로 마이그레이션해야 합니다.
팁
개발 중 마이그레이션 우회
애플리케이션 을 개발하거나 디버깅할 때 영역 을 마이그레이션하는 대신 삭제 하는 것이 나을 수 있습니다. 스키마 불일치로 인해 마이그레이션 이 필요한 경우 데이터베이스 를 자동으로 삭제 deleteRealmIfMigrationNeeded 플래그를 사용하세요.
이 플래그를 true
로 설정한 상태에서는 앱을 프로덕션 환경에 릴리스하지 마세요.
스키마 버전
스키마 버전은 특정 시점의 영역 스키마 상태를 식별합니다. Realm은 각 영역의 스키마 버전을 추적하고 이를 사용하여 각 영역의 객체를 올바른 스키마에 매핑합니다.
스키마 버전은 영역을 열 때 영역 구성에 선택적으로 포함할 수 있는 오름차순 정수입니다. 클라이언트 애플리케이션이 영역을 열 때 버전 번호를 지정하지 않으면 영역의 기본값은 버전 0
입니다.
중요
단조적 버전 증가
마이그레이션은 영역을 상위 스키마 버전으로 업데이트해야 합니다. 클라이언트 애플리케이션이 Realm의 현재 버전보다 낮은 스키마 버전의 영역을 열거나 지정된 스키마 버전이 Realm의 현재 버전과 동일하지만 다른 객체 스키마를 포함하는 경우 Realm은 오류를 발생시킵니다.
마이그레이션
스키마 업데이트는 Realm에서 마이그레이션 이라고 합니다. 마이그레이션은 영역과 영역에 포함된 모든 객체를 한 스키마 버전에서 최신 버전으로 업데이트합니다.
영역의 현재 버전보다 높은 스키마 버전으로 기존 영역을 열 때마다 스키마 업데이트에 필요한 추가 로직을 정의하는 마이그레이션 함수 를 제공할 수 있습니다. 예를 들면 다음과 같습니다.
속성 값 설정
필드 결합 또는 분할
필드 이름 바꾸기
필드 유형 변경
함수는 영역의 버전 번호에 액세스할 수 있으며 새 스키마에 맞게 영역의 객체를 점진적으로 업데이트합니다.
로컬 마이그레이션 은 다른 Realm과 자동으로 동기화 되지 않는 Realm에 대한 마이그레이션입니다.
참고
동기화된 Realm의 스키마 속성을 수정하려면 Atlas Device Sync 문서에서 데이터 모델 업데이트 를 참조하세요.
스키마 자동 업데이트
스키마 업데이트로 속성이 추가되거나 제거되면 Realm은 자동으로 마이그레이션을 수행할 수 있습니다. schemaVersion
을(를) 증가시키기만 하면 됩니다.
속성 추가
스키마에 속성을 추가하려면 다음과 같이 하세요:
RealmObject
정의에 새 속성을 추가합니다.RealmConfiguration 빌더를 통해 스키마 버전을 설정합니다.
업데이트된 객체 스키마 가 기본값 을 지정하면 Realm 은 새 속성에 대한 값을 자동으로 설정합니다. 업데이트된 객체 스키마 에 기본값 이 지정되어 있지 않은 경우 마이그레이션 기능을 통해 새 속성 의 값을 수동으로 설정하다 해야 합니다.
예시
스키마 버전 1
을 사용하는 영역에는 이름, 성, 연령 속성이 포함된 Realm 객체 유형 Person
이 있습니다.
// Realm schema version 1 class Person : RealmObject { var firstName: String = "" var lastName: String = "" var age: Int = 0 }
개발자가 Person
클래스에 email
필드를 추가합니다.
// Realm schema version 2 class Person : RealmObject { var firstName: String = "" var lastName: String = "" var age: Int = 0 var email: String? = null }
업데이트된 Person
스키마를 준수하도록 영역을 변경하려면 개발자는 영역의 스키마 버전을 2
로 설정합니다.
val config = RealmConfiguration.Builder( schema = setOf(Person::class) ) .schemaVersion(2) // Sets the new schema version to 2 .build() val realm = Realm.open(config)
속성 삭제
스키마에서 속성을 삭제하려면 다음과 같이 하세요:
객체의 클래스에서 속성을 제거합니다.
RealmConfiguration 빌더를 통해 스키마 버전을 설정합니다.
속성을 삭제해도 기존 객체에는 영향을 미치지 않습니다.
예시
스키마 버전 2
을 사용하는 영역에는 이름, 성, 연령 및 이메일 속성이 포함된 Person
Realm 객체 유형이 있습니다.
// Realm schema version 2 class Person : RealmObject { var firstName: String = "" var lastName: String = "" var age: Int = 0 var email: String? = null }
개발자가 Person
클래스에서 age
필드를 제거합니다.
// Realm schema version 3 class Person : RealmObject { var firstName: String = "" var lastName: String = "" // var age: Int = 0 var email: String? = null }
업데이트된 Person
스키마를 준수하도록 영역을 변경하려면 개발자는 영역의 스키마 버전을 3
로 설정합니다.
val config = RealmConfiguration.Builder( schema = setOf(Person::class) ) .schemaVersion(3) // Sets the new schema version to 3 .build() val realm = Realm.open(config)
스키마 수동 마이그레이션
더 복잡한 스키마 업데이트의 경우, Realm에서는 지정된 객체의 이전 인스턴스를 새 스키마로 수동으로 마이그레이션해야 합니다.
업데이트된 스키마로 Realm을 열 때는 RealmConfiguration에서 다음을 수행해야 합니다.
schemaVersion
속성을 상향합니다.migrationContext를 사용하여 마이그레이션 로직을 정의합니다 .
속성 수정
객체 속성을 수정하려면(예: 속성 유형 이름 변경, 병합, 분할 또는 변경):
객체 스키마에서 속성을 변경합니다.
증가된 스키마 버전과 기존 객체를 새 속성을 사용하도록 매핑하는 마이그레이션 기능으로 영역을 엽니다.
다음 예에서는 속성 유형을 변경하고, 두 속성을 새 속성으로 병합하고, 기존 속성의 이름을 변경하도록 스키마를 업데이트합니다.
// Realm schema version 1 (oldObject) class Person : RealmObject { var _id: ObjectId = ObjectId() var firstName: String = "" var lastName: String = "" var age: Int = 0 } // Realm schema version 2 (newObject) class Person : RealmObject { var _id: String = "" // change property type var fullName: String = "" // merge firstName and lastName properties var yearsSinceBirth: Int = 0 // rename property }
그런 다음 마이그레이션 함수는 이전 객체 스키마의 수정된 속성과 새 객체 스키마 간에 데이터를 매핑하는 마이그레이션 논리를 정의합니다.
// Use the configuration builder to open the realm with the newer schema version // and define the migration logic between your old and new realm objects val config = RealmConfiguration.Builder( schema = setOf(Person::class) ) .schemaVersion(2) // Set the new schema version to 2 .migration(AutomaticSchemaMigration { it.enumerate(className = "Person") { oldObject: DynamicRealmObject, newObject: DynamicMutableRealmObject? -> newObject?.run { // Change property type set( "_id", oldObject.getValue<ObjectId>(fieldName = "_id").toString() ) // Merge properties set( "fullName", "${oldObject.getValue<String>(fieldName = "firstName")} ${oldObject.getValue<String>(fieldName = "lastName")}" ) // Rename property set( "yearsSinceBirth", oldObject.getValue<String>(fieldName = "age") ) } } }) .build() val realm = Realm.open(config)
참고
스키마 업데이트 에 RealmObject 를 EmbeddedRealmObject 로 변환하는 작업이 포함된 경우 마이그레이션 기능은 내장된 객체 에 연결된 상위 객체 가 정확히 하나 있는지 확인해야 합니다. 포함된 객체는 상위 객체 와 독립적으로 존재할 수 없습니다.
기타 마이그레이션 작업
다른 영역 스키마 마이그레이션을 수행하려면 AutomaticSchemaMigration.MigrationContext
인터페이스의 다음 속성을 사용합니다:
oldRealm: 이전 스키마 버전으로 마이그레이션하기 전에 존재했던 영역입니다. 동적 사용하면 클래스 API Realm string 이름의 표현으로 객체를 찾을 수 있습니다.
newRealm: 새 스키마 버전을 사용하여 마이그레이션 한 후 존재하는 영역 입니다.
oldRealm
및 newRealm
에서 얻은 모든 객체는 마이그레이션 함수의 범위에서만 유효합니다.
마이그레이션이 끝날 무렵에는 스키마 업데이트의 영향을 받는 모든 데이터를 이전 영역에서 새 영역으로 마이그레이션해야 합니다. 스키마 업데이트의 영향을 받지만 마이그레이션되지 않은 데이터는 모두 소실됩니다.
val config = RealmConfiguration.Builder( schema = setOf(Person::class) ) .schemaVersion(2) .migration(AutomaticSchemaMigration { migrationContext -> val oldRealm = migrationContext.oldRealm // old realm using the previous schema val newRealm = migrationContext.newRealm // new realm using the new schema // Dynamic query for all Persons in old realm val oldPersons = oldRealm.query(className = "Person").find() for (oldPerson in oldPersons) { // Get properties from old realm val firstName: String = oldPerson.getValue( propertyName = "firstName", String::class ) // Get objects from old realm as dynamic realm objects val pet: DynamicRealmObject? = oldPerson.getObject( propertyName = "pets" ) } // Get migrated objects from the new realm as mutable objects val oldPerson: DynamicMutableRealmObject? = newRealm.findLatest(oldPersons[0]) oldPerson?.let { it.set("fullName", "Crow T. Robot") } // Create an object in the new realm and set property values val newPerson = newRealm.copyToRealm( DynamicMutableRealmObject.create( type = "Person", mapOf( "_id" to "123456", "fullName" to "Tom Servo", "yearsSinceBirth" to 33, ) ) ) }) .build() val realm = Realm.open(config)