如何执行更好的 SwiftRealm 迁移值
How perform a better SwiftRealm migration value
我在 iOS 和 Android 上使用 Realm Swift 和 Realm-java。我需要实施数据库迁移以更新数据库中的值。
在 Swift 上,迁移按如下方式完成:currentVersion -> latestVersion。在 Android 上:v1 -> v2 -> latestVersion。
以下示例显示 iOS 上的迁移 0 -> 1 和 1 -> 2:
- 0 -> 1 = V1:创建一个新的奇幻电影类别(由
两部电影已经存在于数据库中)
- 1 -> 2 = V2:添加新的
精彩类别电影已创建
迁移 0 -> 1 :
/// 将版本 0 迁移到版本 1 的函数。
/// 创建奇幻电影类别和关联
///
/// - 参数迁移:迁移实例。
static func migrateFrom0To1(_迁移:迁移){
// 为 Fantastic 类别添加的电影。
让 existingFilmToAdd: [String] = ["STAR_WARS", "HARRY_POTTER"]
// 获取存储的电影。
var filmToSet:[MigrationObject] = []
migration.enumerateObjects(ofType: Film.className()) { _, filmDb 在
让 key = filmDb!["filmKey"] 作为!细绳
如果 existingFilmToAdd.contains(键) {
filmToSet.append(电影数据库!)
}
}
// 创建小说类别。
让 fantasticCategory = migration.create(Category.className())
fantasticCategory["categoryKey"] = "FANTASTIC"
fantasticCategory["name"] = "Fantastic"
fantasticCategory["films"] = 电影集
}
迁移 0/1 -> 2
/// 将版本 0 迁移到版本 1 的函数。
/// 创建奇幻电影类别和关联
///
/// - 参数迁移:迁移实例。
static func migrateFrom0To1(_迁移:迁移){
// 为 Fantastic 类别添加的电影。
让 existingFilmToAdd: [String] = ["STAR_WARS", "HARRY_POTTER"]
// 创建超人电影
让超人 = migration.create(Film.className())
超人["filmKey"] = "SUPERMAN"
超人["name"] = "Superman"
超人["time"] = 2
// 获取存储的电影。
var filmToSet:[MigrationObject] = []
migration.enumerateObjects(ofType: Film.className()) { _, filmDb 在
让 key = filmDb!["filmKey"] 作为!细绳
如果 existingFilmToAdd.contains(键) {
filmToSet.append(电影数据库!)
}
}
filmToSet.append(超人)
// 创建小说类别。
让 fantasticCategory= migration.create(Category.className())
fantasticCategory["categoryKey"] = "FANTASTIC"
fantasticCategory["name"] = "Fantastic"
fantasticCategory["films"] = 电影集
}
/// 将版本 1 迁移到版本 2 的函数。
/// 在精彩类别中添加电影
///
/// - 参数迁移:迁移实例。
static func migrateFrom1To2(_迁移:迁移){
// 创建超人电影
让超人 = migration.create(Film.className())
超人["filmKey"] = "SUPERMAN"
超人["name"] = "Superman"
超人["time"] = 2
// 获取存储的电影。
var filmToSet:[MigrationObject] = []
// 更新奇幻电影
migration.enumerateObjects(ofType: Category.className()) { _, migrationCategory in
让 categoryKey = migrationMarket!["categoryKey"] 作为!细绳
如果类别键 == "FANTASTIC" {
让 oldFilm = migrationCategory!["films"] 作为!列表
对于 oldFilm 中的电影 {
filmsToSet.append(电影)
}
filmsToSet.append(超人)
迁移类别!["films"] = filmsToSet
}
}
}
如果应用程序已经安装在 V1 中,将执行迁移 1 -> 2,很简单,此迁移将创建一个新的超人电影并将其添加到先前存储在数据库中的 Fantastic 类别中。
如果是第一次安装:0 -> 2 将被执行。
Fantastic 类别在 0 -> 1 中创建,但在迁移 1 -> 2 中尚不可用,因为迁移尚未完成。我必须修改函数 0 -> 1 迁移函数来创建超人电影并在创建时添加到 Fantastic 类别。
这个例子非常简单,因为数据很简单,但是当我们有更多的值要添加和修改时,迁移就会变得越来越复杂。
在 Android 没问题,迁移一个接着一个,因为数据在每个迁移函数结束时在数据库中可用。 swift 上的迁移实施起来越来越复杂。
我想像 Android 迁移一样进行 Swift 迁移 运行。查看文档和不同的票证后,我找不到解决方案。您有解决问题的解决方案或新架构吗?
注意:解决方案必须始终为我提供迁移数据库架构的可能性
您可以使用类似的方式迁移您的领域。
Realm.Configuration.defaultConfiguration = Realm.Configuration(schemaVersion: 2,
migrationBlock: { (migration, oldSchemaVersion) in
migrate(oldScema: oldSchemaVersion, migration: migration)
})
并且在 migrate(oldScema:, migration:) 函数中,您可以检查旧架构版本并添加相应的操作。例如:
func migrate(oldScema: Int, migration: Migration) {
if oldScema < 1 {
// Migrate 0 -> 1
}
if oldScema < 2 {
// Migrate 1 -> 2
}
// etc for other migrations
}
我找到了答案:
我通过在从 oldSchemaVersion 开始到新 Schema 版本的循环中使用 performMigration 来进行多次小迁移。
</p>
<pre><code>/// Define migration block.
private let migrationBlock: MigrationBlock = { migration, oldSchemaVersion in
switch oldSchemaVersion {
case 0:
Migrations.migrateFrom0To1(migration)
case 1:
Migrations.migrateFrom1To2(migration)
case 2:
Migrations.migrateFrom2To3(migration)
case 3:
Migrations.migrateFrom3To4(migration)
case 4:
Migrations.migrateFrom4To5(migration)
case 5:
Migrations.migrateFrom5To6(migration)
default:
break
}
}
/// Initialize realm configuration.
///
/// - Throws: If error during realm configuration.
private func initializeRealm(realmConfiguration: Realm.Configuration?) throws {
// Init Realm configuration.
var config: Realm.Configuration
if realmConfiguration == nil {
config = Realm.Configuration(schemaVersion: currentSchemaVersion)
// Get current schema version of the database before migration.
let oldSchemaVersion = try schemaVersionAtURL(config.fileURL!)
print("oldSchemaVersion: \(oldSchemaVersion) currentSchemaVersion: \(currentSchemaVersion)")
// Perform all migrations one by one
// (old version to new version) and keep last config.
if oldSchemaVersion < currentSchemaVersion {
for tmpCurrentSchemaVersion in oldSchemaVersion...currentSchemaVersion {
config = Realm.Configuration(schemaVersion: tmpCurrentSchemaVersion, migrationBlock: migrationBlock)
try! Realm.performMigration(for: config)
}
}
} else {
config = realmConfiguration!
}
self.realm = try! Realm(configuration: config)
}
我在 iOS 和 Android 上使用 Realm Swift 和 Realm-java。我需要实施数据库迁移以更新数据库中的值。 在 Swift 上,迁移按如下方式完成:currentVersion -> latestVersion。在 Android 上:v1 -> v2 -> latestVersion。
以下示例显示 iOS 上的迁移 0 -> 1 和 1 -> 2:
- 0 -> 1 = V1:创建一个新的奇幻电影类别(由 两部电影已经存在于数据库中)
- 1 -> 2 = V2:添加新的 精彩类别电影已创建
迁移 0 -> 1 :
/// 将版本 0 迁移到版本 1 的函数。
/// 创建奇幻电影类别和关联
///
/// - 参数迁移:迁移实例。
static func migrateFrom0To1(_迁移:迁移){
// 为 Fantastic 类别添加的电影。
让 existingFilmToAdd: [String] = ["STAR_WARS", "HARRY_POTTER"]
// 获取存储的电影。
var filmToSet:[MigrationObject] = []
migration.enumerateObjects(ofType: Film.className()) { _, filmDb 在
让 key = filmDb!["filmKey"] 作为!细绳
如果 existingFilmToAdd.contains(键) {
filmToSet.append(电影数据库!)
}
}
// 创建小说类别。
让 fantasticCategory = migration.create(Category.className())
fantasticCategory["categoryKey"] = "FANTASTIC"
fantasticCategory["name"] = "Fantastic"
fantasticCategory["films"] = 电影集
}
迁移 0/1 -> 2
/// 将版本 0 迁移到版本 1 的函数。
/// 创建奇幻电影类别和关联
///
/// - 参数迁移:迁移实例。
static func migrateFrom0To1(_迁移:迁移){
// 为 Fantastic 类别添加的电影。
让 existingFilmToAdd: [String] = ["STAR_WARS", "HARRY_POTTER"]
// 创建超人电影
让超人 = migration.create(Film.className())
超人["filmKey"] = "SUPERMAN"
超人["name"] = "Superman"
超人["time"] = 2
// 获取存储的电影。
var filmToSet:[MigrationObject] = []
migration.enumerateObjects(ofType: Film.className()) { _, filmDb 在
让 key = filmDb!["filmKey"] 作为!细绳
如果 existingFilmToAdd.contains(键) {
filmToSet.append(电影数据库!)
}
}
filmToSet.append(超人)
// 创建小说类别。
让 fantasticCategory= migration.create(Category.className())
fantasticCategory["categoryKey"] = "FANTASTIC"
fantasticCategory["name"] = "Fantastic"
fantasticCategory["films"] = 电影集
}
/// 将版本 1 迁移到版本 2 的函数。
/// 在精彩类别中添加电影
///
/// - 参数迁移:迁移实例。
static func migrateFrom1To2(_迁移:迁移){
// 创建超人电影
让超人 = migration.create(Film.className())
超人["filmKey"] = "SUPERMAN"
超人["name"] = "Superman"
超人["time"] = 2
// 获取存储的电影。
var filmToSet:[MigrationObject] = []
// 更新奇幻电影
migration.enumerateObjects(ofType: Category.className()) { _, migrationCategory in
让 categoryKey = migrationMarket!["categoryKey"] 作为!细绳
如果类别键 == "FANTASTIC" {
让 oldFilm = migrationCategory!["films"] 作为!列表
对于 oldFilm 中的电影 {
filmsToSet.append(电影)
}
filmsToSet.append(超人)
迁移类别!["films"] = filmsToSet
}
}
}
如果应用程序已经安装在 V1 中,将执行迁移 1 -> 2,很简单,此迁移将创建一个新的超人电影并将其添加到先前存储在数据库中的 Fantastic 类别中。
如果是第一次安装:0 -> 2 将被执行。 Fantastic 类别在 0 -> 1 中创建,但在迁移 1 -> 2 中尚不可用,因为迁移尚未完成。我必须修改函数 0 -> 1 迁移函数来创建超人电影并在创建时添加到 Fantastic 类别。
这个例子非常简单,因为数据很简单,但是当我们有更多的值要添加和修改时,迁移就会变得越来越复杂。
在 Android 没问题,迁移一个接着一个,因为数据在每个迁移函数结束时在数据库中可用。 swift 上的迁移实施起来越来越复杂。
我想像 Android 迁移一样进行 Swift 迁移 运行。查看文档和不同的票证后,我找不到解决方案。您有解决问题的解决方案或新架构吗?
注意:解决方案必须始终为我提供迁移数据库架构的可能性
您可以使用类似的方式迁移您的领域。
Realm.Configuration.defaultConfiguration = Realm.Configuration(schemaVersion: 2,
migrationBlock: { (migration, oldSchemaVersion) in
migrate(oldScema: oldSchemaVersion, migration: migration)
})
并且在 migrate(oldScema:, migration:) 函数中,您可以检查旧架构版本并添加相应的操作。例如:
func migrate(oldScema: Int, migration: Migration) {
if oldScema < 1 {
// Migrate 0 -> 1
}
if oldScema < 2 {
// Migrate 1 -> 2
}
// etc for other migrations
}
我找到了答案:
我通过在从 oldSchemaVersion 开始到新 Schema 版本的循环中使用 performMigration 来进行多次小迁移。
</p>
<pre><code>/// Define migration block.
private let migrationBlock: MigrationBlock = { migration, oldSchemaVersion in
switch oldSchemaVersion {
case 0:
Migrations.migrateFrom0To1(migration)
case 1:
Migrations.migrateFrom1To2(migration)
case 2:
Migrations.migrateFrom2To3(migration)
case 3:
Migrations.migrateFrom3To4(migration)
case 4:
Migrations.migrateFrom4To5(migration)
case 5:
Migrations.migrateFrom5To6(migration)
default:
break
}
}
/// Initialize realm configuration.
///
/// - Throws: If error during realm configuration.
private func initializeRealm(realmConfiguration: Realm.Configuration?) throws {
// Init Realm configuration.
var config: Realm.Configuration
if realmConfiguration == nil {
config = Realm.Configuration(schemaVersion: currentSchemaVersion)
// Get current schema version of the database before migration.
let oldSchemaVersion = try schemaVersionAtURL(config.fileURL!)
print("oldSchemaVersion: \(oldSchemaVersion) currentSchemaVersion: \(currentSchemaVersion)")
// Perform all migrations one by one
// (old version to new version) and keep last config.
if oldSchemaVersion < currentSchemaVersion {
for tmpCurrentSchemaVersion in oldSchemaVersion...currentSchemaVersion {
config = Realm.Configuration(schemaVersion: tmpCurrentSchemaVersion, migrationBlock: migrationBlock)
try! Realm.performMigration(for: config)
}
}
} else {
config = realmConfiguration!
}
self.realm = try! Realm(configuration: config)
}