オブジェクトモデルの変更 - Kotlin SDK
注意
同期された Realm のスキーマ プロパティの変更
次のページでは、ローカル Realm のスキーマ プロパティを変更する方法を示します。 同期された Realm のスキーマ プロパティを変更する方法を学びます。
Overview
Realm オブジェクトモデル を作成した後、オブジェクト スキーマに変更を加えることができます。 スキーマに加える変更のタイプに応じて、変更を自動的に適用することも、新しいスキーマへの手動更新が必要になることもあります。
Realm は、Realm オブジェクトモデルからプロパティを追加または削除すると、Realmオブジェクト スキーマを自動的に更新します。 スキーマのバージョンを更新する必要があるだけです。
その他のすべてのスキーマ変更では、特定のオブジェクトの古いインスタンスを新しいスキーマに手動で移行する必要があります。
Tip
開発中のバイパス移行
アプリケーションを開発またはデバッグする際には、Realm を移行するのではなく、 Realm を削除することをお勧めします。 スキーマの不一致により移行が必要になる場合に、データベースを自動的に削除するには、 deleteRealmIfMigrationNetedフラグを使用します。
このフラグを true
に設定して、アプリを本番環境にリリースしないでください。
スキーマ バージョン
スキーマ バージョンは、ある時点におけるRealm スキーマの状態を識別します。 Realm は各 Realm のスキーマ バージョンを追跡し、それを使用して各 Realm 内のオブジェクトを正しいスキーマにマッピングします。
スキーマ バージョンは昇順の整数であり、 Realm を開くときに任意で Realm 構成に含めることができます。 クライアント アプリケーションが Realm を開くときにバージョン番号を指定しない場合、Realm はデフォルトでバージョン0
になります。
重要
バージョンを単調に増加させる
移行によって、Realm をより高いスキーマ バージョンに更新する必要があります。 Realm は、Realm の現在のバージョンよりも低いスキーマ バージョンでクライアント アプリケーションが Realm を開き、または指定されたスキーマ バージョンが Realm の現在のバージョンと同じであるが、異なるオブジェクト スキーマを含む場合にエラーをスローします。
移行
Realm では、スキーマの更新は移行と呼ばれます。 移行により、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
スキーマに準拠するように Realm を変更するには、開発者は Realm のスキーマ バージョンを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
を使用する Realm には、名、姓、年数、電子メールのプロパティを持つPerson
オブジェクトタイプがあります。
// 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
スキーマに準拠するように Realm を変更するには、開発者は Realm のスキーマ バージョンを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を開きます。
次の例では、プロパティタイプの変更、2 つのプロパティを新しいプロパティにマージする方法、および既存のプロパティの名前を変更するためにスキーマをアップデートします。
// 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を埋め込みRealm オブジェクトに変換することが含まれている場合、移行関数によって、埋め込みオブジェクトの親オブジェクトが 1 つだけ にリンクされていることを確認する必要があります。 埋め込みオブジェクトは、親オブジェクトと独立して存在することはできません。
その他の移行タスク
その他の Realm スキーマ移行を実行するには、 AutomaticSchemaMigration.MigrationContext
インターフェースの次のプロパティを使用します。
oldRealm : 前のスキーマ バージョンを使用する移行前に存在していたRealm。 動的 API を使用すると、クラス名の string 表現によって Realm オブジェクトを検索できます。
newRealm : 新しいスキーマ バージョンを使用した移行後に存在するRealm。
oldRealm
とnewRealm
から取得されたオブジェクトは、移行関数の範囲内でのみ有効です。
移行が終了するまでに、スキーマ更新の影響を受けるすべてのデータを、古い Realm から新しい Realm に移行する必要があります。 移行されていないスキーマ更新の影響を受けるデータは、失われます。
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)