【问题标题】:Is there a way to rebuild Dexie keys?有没有办法重建 Dexie 密钥?
【发布时间】:2017-08-23 17:19:16
【问题描述】:

我有一个使用 Dexie 的工作应用程序。升级到 iOS 10.3 后,按键查找不起作用。 (这实际上是一个 indexeddb 问题,而不是 Dexie 本身,我敢肯定。)我仍然感到震惊,但我已经能够通过执行 db.table.each(function(p) { },并且键中使用的字段在那里并且正确。但是如果我这样做 db.table.get(primarykey, function(p) {} 要么 db.table.where("somekey").equals(nonprimarykey).first(function(p) {} p 未定义。

我尝试做 .db.table.each 然后将每个检索到的对象放回去,看看是否会重建密钥,它在 Firefox 中工作,但在 Safari 或 Chrome 中不起作用(仍然无法通过钥匙)。

我还尝试指定具有相同密钥结构和空升级的新版本,但没有做任何事情(但我只在 Chrome 中尝试过)。

如果数据库是在安装 10.3 之后创建的,一切都很好,但我希望我的客户不必删除他们的数据库。

有什么方法可以在不丢失数据的情况下修复这个问题?

【问题讨论】:

    标签: ios indexeddb dexie ios10.3


    【解决方案1】:

    这似乎是 Safari 中的一个升级错误,应该在 bugs.webkit.org 上提交。假设这将在那里修复,因为 Safari 团队在遇到严重错误时非常敏感。请归档!

    至于解决方法,我建议重新创建数据库。将数据库复制到新数据库,将其删除,然后复制回来并删除中间副本。下面的代码我还没有验证过,你自己测试一下吧。

    function check_and_fix_IOS_10_3_upgrade_issue () {
        return (somehowCheckIfWeNeedToDoThis) ?
            recreateDatabase() : Promise.resolve();
    }
    
    function recreateDatabase () {
        copyDatabase("dbName", "dbName_tmp").then(()=>{
            return Dexie.delete("dbName");
        }).then(()=>{
            return copyDatabase("dbName_tmp", "dbName");
        }).then(()=>{
            return Dexie.delete("dbName_tmp");
        });
    }
    
    function copyDatabase(fromDbName, toDbName) {
        return new Dexie(fromDbName).open().then(db => {
            let schema = db.tables.reduce((schema, table) => {
                schema[table.name] = [table.schema.primKey.src]
                    .concat(table.schema.indexes.map(idx => idx.src))
                    .join(',');
            }, {});
    
            let dbCopy = new Dexie(toDbName);
            dbCopy.version(db.verno).stores(schema);
    
            return dbCopy.open().then(()=>{
                // dbCopy is now successfully created with same version and schema as source db.
                // Now also copy the data
                return Promise.all(
                    db.tables.map(table =>
                        table.toArray().then(rows => dbCopy.table(table.name).bulkAdd(rows))));
            }).finally(()=>{
                 db.close();
                 dbCopy.close();
            });
        })
    }
    

    关于“somehowCheckIfWeNeedToDoThis”,我无法准确回答该怎么做。也许用户代理嗅探+ cookie(固定时设置持久cookie,这样它就不会一遍又一遍地重新创建)。也许你会找到更好的解决方案。

    然后在你打开你的数据库之前(也许在你的应用程序启动之前)你需要做一些类似的事情:

    check_and_fix_IOS_10_3_upgrade_issue()
        .then(()=>app.start())
        .catch(err => {
            // Display error, to user
        });
    

    【讨论】:

    • 感谢您的想法。并告诉我在哪里报告这个。我同意这是升级中的错误,但不知道在哪里报告。不幸的是,他们似乎很沮丧或很忙。我会继续努力的。
    • 很好,你报告了它。我在 Dexie 上发布了一个问题,供其他用户确认此错误 (github.com/dfahlander/Dexie.js/issues/499)。你有你的 webkit 问题的 URL 吗?我想将 dexie 问题链接到它。
    【解决方案2】:

    我在使用 db.js 库时遇到了同样的问题。我的所有应用数据在升级时都会被擦除。

    根据我的测试,10.2 -> 10.3 升级似乎正在擦除 autoIncrement 设置为 false 的表中的所有数据。升级后仍可访问保存在 autoIncrement=true 表中的数据。

    如果是这种情况,这是一个非常严重的错误。 Safari 的 autoIncrement 功能有很多麻烦,导致我们很多人改用管理自己的 ID。

    我还没有用 vanilla JS 测试过这个理论。如果有人想这样做,请将您的结果添加到bugs.webkit.org ticket

    【讨论】:

    • 我不知道最近是否有对 OS X 的更新,但是有人在桌面 Mac 上使用我的应用程序时遇到了具有相同症状的问题,因此可能不仅仅是 iOS .我不知道这两者有多少同步,如果有的话。