【问题标题】:How perform a better SwiftRealm migration value如何执行更好的 SwiftRealm 迁移价值
【发布时间】:2021-06-02 15:55:00
【问题描述】:

我在 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:



    /// Function to migrate version 0 to version 1.
    /// Create Fantastic film category and associated 
    ///
    /// - Parameter migration: Migration instance.
    static func migrateFrom0To1(_ migration: Migration) {
        // Film to add for Fantastic category.
        let existingFilmToAdd: [String] = ["STAR_WARS", "HARRY_POTTER"]
        // Get stored films.
        var filmToSet: [MigrationObject] = []
        migration.enumerateObjects(ofType: Film.className()) { _, filmDb in
            let key = filmDb!["filmKey"] as! String
            if existingFilmToAdd.contains(key) {
                filmToSet.append(filmDb!)
            }
        }
        // Create Fiction Category.
        let fantasticCategory = migration.create(Category.className())
        fantasticCategory["categoryKey"] = "FANTASTIC"
        fantasticCategory["name"] = "Fantastic"
        fantasticCategory["films"] = filmToSet
    }

迁移 0/1 -> 2



    /// Function to migrate version 0 to version 1.
    /// Create Fantastic film category and associated 
    ///
    /// - Parameter migration: Migration instance.
    static func migrateFrom0To1(_ migration: Migration) {
        // Film to add for Fantastic category.
        let existingFilmToAdd: [String] = ["STAR_WARS", "HARRY_POTTER"]
        // Create Superman Film
        let superman = migration.create(Film.className())
        superman["filmKey"] = "SUPERMAN"
        superman["name"] = "Superman"
        superman["time"] = 2 
        // Get stored films.
        var filmToSet: [MigrationObject] = []
        migration.enumerateObjects(ofType: Film.className()) { _, filmDb in
            let key = filmDb!["filmKey"] as! String
            if existingFilmToAdd.contains(key) {
            filmToSet.append(filmDb!)
            }
        }
        filmToSet.append(superman)
        // Create Fiction Category.
        let fantasticCategory= migration.create(Category.className())
        fantasticCategory["categoryKey"] = "FANTASTIC"
        fantasticCategory["name"] = "Fantastic"
        fantasticCategory["films"] = filmToSet
    }
    
    /// Function to migrate version 1 to version 2.
    /// Add film in Fantastic Category 
    ///
    /// - Parameter migration: Migration instance.
    static func migrateFrom1To2(_ migration: Migration) {
        // Create Superman Film
        let superman = migration.create(Film.className())
        superman["filmKey"] = "SUPERMAN"
        superman["name"] = "Superman"
        superman["time"] = 2 
        // Get stored films.
        var filmToSet: [MigrationObject] = []
        // Update Fantastic film
        migration.enumerateObjects(ofType: Category.className()) { _, migrationCategory in
            let categoryKey = migrationMarket!["categoryKey"] as! String
            if categoryKey == "FANTASTIC" {
                let oldFilm = migrationCategory!["films"] as! List
                for film in oldFilm {
                   filmsToSet.append(film)
                }
                filmsToSet.append(superman)
                migrationCategory!["films"] = filmsToSet
            }
        }
    }

  • 如果应用已经安装在V1中,将执行迁移1 -> 2,很简单,这个迁移创建一个新的超人电影并将其添加到之前存储到数据库中的神奇类别中。

  • 如果是第一次安装:0 -> 2 将被执行。 Fantastic Category 在 0 -> 1 中创建,但在迁移 1 -> 2 中尚不可用,因为迁移尚未完成。我必须修改函数 0 -> 1 迁移函数来创建超人电影并在创建时添加到 Fantastic Category。

这个例子很简单,因为有简单的数据,但是当我们有更多的价值要添加和修改时,它会使迁移变得越来越复杂。

在 Android 上没有问题,迁移会一个接一个,因为在每个迁移函数结束时,数据库中的数据都是可用的。 swift 上的迁移实现起来越来越复杂。

我想让 Swift 迁移像 Android 迁移一样运行。在查看文档和不同的票后,我找不到解决方案。您有解决问题的解决方案或新架构吗?

注意:解决方案必须始终为我提供迁移数据库架构的可能性

【问题讨论】:

    标签: android swift realm realm-migration


    【解决方案1】:

    您可以使用类似的方式迁移您的领域。

    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
    }
    

    【讨论】:

    • 是的,但是如果在迁移 1 中添加数据,在迁移 2 中我想修改这些数据,我也必须修改迁移 1
    【解决方案2】:

    我找到了答案: 我继续通过在循环中使用 performMigration 从 oldSchemaVersion 到新的 Schema 版本来进行多次少量迁移。

    /// 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)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-29
      • 2017-11-24
      • 2015-10-09
      • 2013-02-15
      • 1970-01-01
      • 2012-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多