【问题标题】:Realm dotnet migration callback not being called未调用领域 dotnet 迁移回调
【发布时间】:2017-01-24 20:02:04
【问题描述】:

我正在尝试使用 v0.81.0 版本实现领域迁移

当我在我的一个数据访问对象中安装并运行带有附加字段的应用程序的新版本时,它没有调用领域迁移回调,它只是抛出一个异常 (RealmMigrationNeededException) 告诉我我必须迁移,因为我有向我的一个数据访问对象添加了一个属性。这是我第一次尝试迁移,因此之前未设置架构版本的回调

这是我的代码,任何人都可以看到任何问题。此处使用的加密密钥仅用于示例目的

        try
        {
            var config = new RealmConfiguration("MyExampleDatabase.realm");

            var encryptionKey = new byte[64] // key MUST be exactly this size
                {
              0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
              0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
              0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
              0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
              0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
              0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
              0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
              0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
                };

            config.EncryptionKey = encryptionKey;

            // Start of new code added
            config.MigrationCallback = (migration, oldSchemaVersion) =>
            {
                // do migration here!!
            };

            config.SchemaVersion = 1;
            // End of new code added
            var realm = Realm.GetInstance(config);
            return realm;
        }
        catch (Exception ex)
        {
            // Log error here
        }

【问题讨论】:

    标签: xamarin realm database-migration


    【解决方案1】:

    必须更改领域配置的 SchemaVersion 才能调用迁移回调。

    迁移示例

    初始 RealmObject (SchemaVersion == 1)

    public class POCO : RealmObject
    {
        public string key { get; set; }
        public string value { get; set; }
    }
    

    初始应用(SchemaVersion == 1)

    const ulong currentSchemaVersion = 1;
    var config = new RealmConfiguration()
    {
        SchemaVersion = currentSchemaVersion,
        MigrationCallback = (Migration migration, ulong oldSchemaVersion) =>
        {
            // initial app release / no schema migration
            // This will NOT be called
        }
    };
    var realm = Realm.GetInstance(config);
    realm.WriteAsync((Realm r) =>
    {
        var data = new POCO()
        {
            key = "1",
            value = "1"
        };
        r.Add(data);
    });
    

    RealmObject 在新应用版本中发生变化:

    更新的 RealmObject (SchemaVersion == 2)

    注意:value 的类型从 string 更改为 int

    public class POCO : RealmObject
    {
        public string key { get; set; }
        public int value { get; set; }
    }
    

    更新的应用程序(SchemaVersion == 2)

    const ulong currentSchemaVersion = 2;
    var config = new RealmConfiguration()
    {
        SchemaVersion = currentSchemaVersion,
        MigrationCallback = (Migration migration, ulong oldSchemaVersion) =>
        {
            if (oldSchemaVersion > currentSchemaVersion)
            {
                throw new Exception($"SchemaVersion of {oldSchemaVersion} is unknown");
            }
            if (oldSchemaVersion <= 1)
            {
                // SchemaVersion = 1
                // initial app release / no schema migration
            }
            if (oldSchemaVersion < 2)
            {
                // SchemaVersion = 2,
                // POCO.value changed from string to int
    
                var newPOCOs = migration.NewRealm.All<POCO>();
                var oldPOCOs = migration.OldRealm.All("POCO");
                var count = newPOCOs.Count();
                for (int i = 0; i < count; i++)
                {
                    var oldPOCO = oldPOCOs.ElementAt(i);
                    var newPOCO = newPOCOs.ElementAt(i);
                    newPOCO.value = int.Parse(oldPOCO.value);
                }
            }
        }
    };
    var realm = Realm.GetInstance(config);
    realm.WriteAsync((Realm r) =>
    {
        var data = new POCO()
        {
            key = "2",
            value = 2
        };
        r.Add(data);
    });
    

    【讨论】:

    • 我明白这一点。根据文档“未指定时,领域的架构版本将设置为 0。”所以我的原始应用程序没有设置架构版本,因此可以假定为版本 0。在如上所示的下一个版本中,我将其设置为 1。所以我期待调用迁移回调。那么为什么它没有被调用呢?
    • @rideintothesun 您说您的 Realm 版本是 0.88.1,该版本不存在..(0.82.0 是当前版本),。您的原始数据库是用什么 Realm 版本创建的,您目前使用的是什么版本?即,将架构初始化为 0 的更改是在 github.com/realm/realm-dotnet/pull/768 ... 中完成的
    • 对不起,应该读到 0.81.0。这就是我正在进行的初步开发调查。我的生产版本是 0.77.1。这可以迁移吗?
    • 我现在真正的问题是,如果我有一个使用 v0.77.1 编写的生产应用程序并且现在想将该应用程序升级到使用 v0.81.0 的应用程序,它会检测到迁移。如果不能,我可以强制迁移以将不支持迁移的领域版本桥接到支持迁移的领域吗?
    • @rideintothesun 有多种方法可以“拼凑”它,但也许 Realm 开发人员会有更好的方法:github.com/realm/realm-dotnet/issues/1186
    【解决方案2】:

    总结

    即使旧版本的 Realm 早于迁移,迁移仍然有效。

    加密没有区别。

    原创

    @sushihangover 是对的,但还有更多细微差别。

    只需添加一个属性不需要回调,除非您希望自定义逻辑来填充它。该属性将自动添加到领域中。

    但是,为了确保您打算更改架构,最小的迁移是增加架构编号,如we document。

    您从 0.77.1 开始似乎可能存在问题。查看changelog, 0.77.2 是引入修复的版本Schema 版本号现在从 0 而不是 UInt64.MaxValue 开始

    但是:

    更新测试结果

    简单迁移

    1. 我用 0.77.1 nuget 构建了一个应用并在 iPhone 上运行
    2. 我复制了解决方案并将副本更新为 0.81.0,方法是先删除 Realm,然后添加 0.81.0 包。
    3. 在副本中,我添加了一个简单的整数属性。
    4. 运行迁移的副本刚刚工作

    这些结果让我有点吃惊——我认为我需要明确设置SchemaVersion。

    但后来我意识到,在 0.81.0 中默认的 SchemaVersion 为 0 可能有效,因为旧的 UInt64.MaxValue 被处理为未分配。

    回调测试

    1. 采用上述两种方案,我添加了一个回调方法,如in our Migration docs所述。
    2. 没有调用迁移回调,这不足为奇。
    3. 我明确设置了一个新的config.SchemaVersion,并调用了我的迁移回调。

    底线 - 一切都按预期工作。

    回调测试 - 纯粹在 0.81.0 中 我在重新阅读问题时意识到,您的迁移实验不是从 0.77.1 领域开始,而是从 0.81.0 开始。

    1. 我从 0.81.0 开始使用我的最小架构并运行,因此创建了领域。
    2. 我添加了一个属性和我的迁移回调。
    3. 我设置了SchemaVersion=1
    4. 我运行并调用了迁移回调(意味着初始 SchemaVersion 为 0)。

    这让我对触发异常的实际情况感到有些困惑,因为无论是从旧的 0.71.1 还是当前的 0.81.0 领域迁移,似乎一切都按照 0.81.0 的记录和预期工作。

    按照我在对该问题的评论中提到的另一种理论,我尝试添加加密以查看是否会产生影响(否)。

    【讨论】:

      猜你喜欢
      • 2017-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多