angularjs - IndexedDB key 生成器在 put-transaction 后重置

标签 angularjs ionic-framework indexeddb angularjs-service

这个问题难倒了我。

由于某种原因,indexedDB 中的自动增量键生成器在使用 put-transaction 对现有对象执行和更新后会重置,从而导致数据库中的数据被覆盖。

对于我的应用程序,我使用的是 AngularJS 自行编写的 IndexedDB 服务,并实现了所有基本的 CRUD 功能。 我还可以补充一点,我正在使用 Ionic Framework 进行开发,尽管我怀疑这是罪魁祸首。

考虑到该服务是一项正在进行的工作,我已将对象存储的关键路径默认为“id”,并采用自动增量策略。 然而,给定存储的索引由用户在特定对象中决定。 举个例子:

dbHelper.objectStores = [{'employees', 
    indices: [{indexName: 'name', isUnique: false}, 
              {indexName: 'phone', isUnique: true}]}];

除非已经在数据库中创建,否则这将创建具有索引“name”和“phone”的对象存储“employees”,其中“phone”必须是唯一值,而“name”则不是。

这里是openDB函数的实现。 请注意,dbHelper.objectStores 应该为空,因为由用户在打开数据库之前分配这些属性(否则它是默认的)。

angular.module('dbProvider', [])
.factory('$db', ['$window', function($window) {

// DB Object

var dbHelper = {};

// Properties - Are given defaults unless assigned manually by user before openDB is invoked.

dbHelper.dbName = 'defaultDB';
dbHelper.dbVersion = 1;
dbHelper.objectStores = [];

dbHelper.openDB = function(onCompleteCallback, onErrorCallback) {

        console.log('Atempting to open db with name ' + dbHelper.dbName + '.');

        var request = $window.indexedDB.open(dbHelper.dbName, dbHelper.dbVersion);

      // Invoked by indexedDB if version changes

      request.onupgradeneeded = function(e) {

        console.log('Version change. Current version: ' + dbHelper.dbVersion);

        var db = e.target.result;

        e.target.transaction.onerror = onErrorCallback;

        if(dbHelper.objectStores.length === 0) {
            dbHelper.objectStores.push({name:'defaultStore', indices: []});
        }

        for(var store in dbHelper.objectStores) {

            if(db.objectStoreNames.contains(dbHelper.objectStores[store].name)) {

                console.log(dbHelper.objectStores[store].name + ' deleted.');
                db.deleteObjectStore(dbHelper.objectStores[store].name);

            }

            var newStore = db.createObjectStore(dbHelper.objectStores[store].name, {keyPath: "id", autoIncrement: true});

            for(var index in dbHelper.objectStores[store].indices) {

                newStore.createIndex(dbHelper.objectStores[store].indices[index].indexName,
              dbHelper.objectStores[store].indices[index].indexName,  
              {unique : dbHelper.objectStores[store].indices[index].isUnique});
            }

            console.log(dbHelper.objectStores[store].name + ' created.');
        }

    };

    request.onsuccess = function(e) {
        console.log('DB ' + dbHelper.dbName + ' open.');
        dbHelper.indexedDB.db =  e.target.result;

        onCompleteCallback();
    };

    request.onerror = onErrorCallback;

};

以下是一些 CRUD 函数(有问题的函数):

dbHelper.findItemWithIndex = function(keyValue, storename,
    onCompleteCallback,onErrorCallback) {

    var db = dbHelper.indexedDB.db;
    var trans = db.transaction([storename], "readwrite");
    var store = trans.objectStore(storename);

    var index = store.index(keyValue.key);
    index.get(keyValue.value).onsuccess = function(event) {

    onCompleteCallback(event.target.result);

    };

};

dbHelper.addItemToStore = function(item, storename, 
    onCompleteCallback, onErrorCallback) {

    var db = dbHelper.indexedDB.db;
    var trans = db.transaction([storename], "readwrite");
    var store = trans.objectStore(storename);

    var request = store.add(item);

    trans.oncomplete = onCompleteCallback;

    request.onerror = onErrorCallback;
};

dbHelper.deleteItemFromStore = function(itemId, storename, 
    onCompleteCallback, onErrorCallback) {

    var db = dbHelper.indexedDB.db;
    var trans = db.transaction([storename], "readwrite");
    var store = trans.objectStore(storename);

    var request = store.delete(itemId);

    trans.oncomplete = onCompleteCallback;

    request.onerror = onErrorCallback;

};

dbHelper.updateItem = function(item, storename, onCompleteCallback, onErrorCallback) {

    var db = dbHelper.indexedDB.db;
    var trans = db.transaction([storename], "readwrite");
    var store = trans.objectStore(storename);

    var request = store.put(item);

    trans.oncomplete = onCompleteCallback;

    request.onerror = onErrorCallback;


};

最后,来自调用事务的 Controller 的代码。 这里的策略是,在第一次持久化项目时使用 addItemToStore 函数将项目添加到数据库中,然后使用 updateItem 函数。 第一次添加后,会立即获取对象,以便继续使用数据库中指定的 id 对其进行处理。

$scope.updateTemplate = function() {

    console.log('Saving..');

    var onCompleteCallback = {};

    if(!$scope.formTemplate.firstSave) {
        onCompleteCallback = $scope.updateModel;
    } else {
        $scope.formTemplate.firstSave = false;
            onCompleteCallback = $scope.setId;
    }

    $db.updateItem($scope.formTemplate, $scope.objectStore.name, 
        onCompleteCallback, $scope.dbError);

};

$scope.newItem = function() {

    $db.addItemToStore($scope.formTemplate, $scope.objectStore.name, 
        $scope.setId, $scope.dbError);

};

$scope.setId = function() {

    $db.findItemWithIndex(
        {key: 'title', 
        value: $scope.formTemplate.title},
        $scope.objectStore.name,
        function(result) {
            console.log(JSON.stringify(result));
            $scope.formTemplate = result;
        },
        function(error) {
            $scope.dbError(error);
        });

}

到了这里,一切都会陷入 hell 。 我添加一个对象,返回到另一个 View 并在 id=1 的列表中找到它。 我添加另一个对象,返回到 ListView ,它的 id=2 就在那里。 等等等等..

然后,在使用 $scope.updateTemplate 函数更新任一对象后(该函数也像魅力一样工作),事情变得有趣:

添加的下一个对象的 id=1 并完全删除之前的旧数字。

接下来的对象也会获得 id,从而导致它们替换已经存在的对象。

什么可能导致这种情况?

为了进行测试,我在 OS 10.10 中使用 Safari 8,并部署到带有 KitKat 4.4.2 的 LGG2。

最佳答案

说实话,我浏览了一下,但我看到了这个,“Safari 8” - 最新的 iOS 和 Safari 对 IndexedDB 有严重的错误:http://www.raymondcamden.com/2014/9/25/IndexedDB-on-iOS-8--Broken-Bad

关于angularjs - IndexedDB key 生成器在 put-transaction 后重置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26708479/

相关文章:

javascript - 自定义 Angular 指令广播一个事件但不广播给嵌套的 child ?

android - MediaPlayer 插件不工作

javascript - 在 Jasmine 中使用 $q 测试 AngularJS 服务

indexeddb - 通过多个键从indexedDB获取所有数据

javascript - 我如何知道 IDBCursor 达到了它的最后一个值?

css - 添加和删​​除(切换) Bootstrap 选项卡的折叠类

javascript - angularjs - $http 读取 json 并等待回调

javascript - 如何拆分 AngularJS Controller ?

ios - iOS自定义声音通知位置

angularjs - 在 AngularJS 中替换字符串中的字符