更新 Realm 对象模式 - Flutter SDK
首次创建 Realm 对象后,您可以更改其模式。根据您对模式所做的更改类型,可以自动应用这些更改,也可以手动将其更新到新模式。手动模式更新在 Realm 中称为迁移。
在 Realm 对象模型中添加或删除属性时,您可以自动更新Realm 对象Realm 对象模式。 有关更多信息,请参阅自动更新模式部分。
您必须对所有其他模式更改执行手动迁移。 有关更多信息,请参阅“手动迁移模式”部分。
提示
在开发期间绕过迁移
在开发或调试应用程序时,您可能更愿意删除而不是迁移域 。使用 LocalConfiguration.shouldDeleteIfMigrationNeeded 属性,以便在模式不匹配而需要迁移时自动删除数据库。
重要
修改同步 Realm 的模式属性
此页面上的内容仅应用于本地 Realm。 对于使用Atlas Device Sync与MongoDB Atlas同步数据的Realm ,模式迁移功能有所不同。 请参阅更新同步Realm的模式部分。
模式版本
模式版本可标识 Realm 模式在某个时间点的状态。Realm 会跟踪每个 Realm 的模式版本,并使用该信息将每个 Realm 中的对象映射到正确的模式。
模式版本是指打开 Realm 时可以选择性地包含在 Realm 配置中的递增整数。如果客户端应用程序在打开 Realm 时未指定版本号,则该 Realm 默认采用 0
版本。
手动迁移必须将 Realm 更新到更高的模式版本。如果客户端应用程序打开的 Realm 的模式版本低于该 Realm 的当前版本,或是指定的模式版本与该 Realm 的当前版本相同但包含不同对象模式,则 Realm 会抛出错误。
自动更新模式
Realm 可以自动迁移已添加和已删除的属性。进行这些更改时,您必须更新模式版本。
添加属性
要向在模式中添加属性,请执行以下操作:
将新属性添加到对象的
RealmModel
类中。将模式版本设置为 Realm 的 配置对象。
例子
使用模式版本 1
的 Realm 有附带 firstName
和 lastName
属性的 Person
对象类型。开发者决定将 age
属性添加到 _Person
RealmModel 类。
要更改域以符合更新的Person
模式,开发者将 Realm 的模式版本设置为2
。
()class _Person { late String firstName; late String lastName; late int age; }
final config = Configuration.local([Person.schema], schemaVersion: 2); final realm = Realm(config);
删除属性
要从模式中删除属性,请执行以下操作:
从对象的
RealmModel
类中删除该属性。在 Realm 的配置中,包括重新生成的
RealmObject.schema
并递增schemaVersion
。
删除属性不会影响现有对象。
例子
使用模式版本 1
的 Realm 有附带 weight
属性的 Person
对象类型。开发者决定从模式中删除该属性。
为了迁移 Realm 以符合更新的Person
模式,开发者将 Realm 的模式版本设置为2
。
final config = Configuration.local([Person.schema], schemaVersion: 2); final realm = Realm(config);
手动迁移模式
对于更复杂的模式更新,Realm 要求您手动将给定对象的旧实例迁移到新模式。
使用更新的模式打开 Realm 时,必须在 Realm 的 Configuration
(配置)中执行以下操作:
将
schemaVersion
属性相加。在迁移回调中定义 迁移 逻辑 Realm 配置 的属性 。迁移回调具有以下参数:
migration
:具备当前域、迁移目标域以及迁移操作辅助方法访问权限的迁移实例。oldSchemaVersion
:设备上 Realm 的上一个模式版本的编号。
以下各节说明如何执行各种迁移操作。
删除对象类型
要从 Realm 中删除某一类型的所有对象,请将对象模式名称的string 表示形式传递给 Migration.deleteType()。
如果模式的上一版本有 Realm 对象类型,而模式的新版本没有,则此功能非常有用。
final configWithoutPerson = Configuration.local([Car.schema], schemaVersion: 2, migrationCallback: ((migration, oldSchemaVersion) { // Between v1 and v2 we removed the Person type migration.deleteType('Person'); })); final realmWithoutPerson = Realm(configWithoutPerson);
为属性重命名
使用 Migration.renameProperty() 重命名模式属性。
final configWithRenamedAge = Configuration.local([Person.schema, Car.schema], schemaVersion: 2, migrationCallback: ((migration, oldSchemaVersion) { // Between v1 and v2 we renamed the Person 'age' property to 'yearsSinceBirth' migration.renameProperty('Person', 'age', 'yearsSinceBirth'); })); final realmWithRenamedAge = Realm(configWithRenamedAge);
其他迁移任务
要执行其他 Realm 模式迁移,请在迁移回调函数中使用 Migration
对象的以下属性:
Migration.oldRealm :迁移之前的模式版本中存在的 Realm。 您必须使用
oldRealm
的动态 API 访问其对象,因为您无法使用基于类型的标准查询。 动态API 允许您通过类名称的 表示形式查找Realm string对象。Migration.newRealm :迁移后存在的 Realm。 在迁移回调结束时,您必须将受模式更新影响的所有数据从
oldRealm
迁移到newRealm
中。 任何受模式更新影响但未迁移的数据都将丢失。
如需在新域中查找旧域中对象的实例,可以使用 Migration.findInNewRealm()。如需访问旧模式中对象的属性,请使用 RealmObjectBase.dynamic API。
final configWithChanges = Configuration.local([Person.schema, Car.schema], schemaVersion: 2, migrationCallback: ((migration, oldSchemaVersion) { // Dynamic query for all Persons in previous schema final oldPeople = migration.oldRealm.all('Person'); for (final oldPerson in oldPeople) { // Find Person instance in the updated realm final newPerson = migration.findInNewRealm<Person>(oldPerson); if (newPerson == null) { // That person must have been deleted, so nothing to do. continue; } // Use dynamic API to get properties from old schema and use in the // new schema newPerson.fullName = "${oldPerson.dynamic.get<String>("firstName")} ${oldPerson.dynamic.get<String>("lastName")}"; // convert `id` from ObjectId to String final oldId = oldPerson.dynamic.get<ObjectId>("id"); newPerson.id = oldId.toString(); } })); final realmWithChanges = Realm(configWithChanges);
修改同步 Realm 的模式
更新同步 Realm 的模式与更新仅限本地 Realm 的模式是两个不同的过程。
同步 Realm 没有模式版本,会自动将对象迁移到最新模式。同步 Realm 仅支持不间断的模式更改。
了解如何修改同步域的模式属性。