2014-11-03 22 views
2

這個問題讓我難堪。轉儲交易後IndexedDB密鑰生成器重置

由於某些原因,indexedDB中的自動增量密鑰生成器在使用put-transaction執行和更新現有對象後重置,導致覆蓋數據庫中的數據。

對於我的應用程序,我使用了一個爲angularJS自我編寫的IndexedDB服務,並實現了所有基本的CRUD功能。 我也可以補充說我正在用Ionic Framework開發,即使我懷疑這是責任。

考慮到服務是一個工作進行中,我已經通過自動增量策略讓對象存儲的關鍵路徑默認爲「id」。 然而,給定商店的指數取決於用戶在特定對象中的決定。 作爲一個例子:

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

這,除非在db已經創建,創建對象存儲「僱員」與索引「名稱」和「電話」,在「電話」必須是唯一值而'名稱'不會。

這裏是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; 


}; 

最後,從其中交易被調用控制器的代碼。 這裏的策略是,在第一次保存項目時,使用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); 
     }); 

} 

它在這裏一切都會到地獄。 我添加一個對象,回到另一個視圖,並在id = 1的列表中找到它。 我添加了另一個對象,回到列表視圖,並且它的id = 2。 而且等等等等..

然後,更新或者與$ scope.updateTemplate功能,這也就像一個魅力的對象後,事情就變得有趣:

添加的下一個對象獲得ID = 1,並從早期完全擦除舊的舊數字。

接下來的對象也會得到id,導致它們替換已經存在的對象。

這是什麼原因造成的?

爲了測試,我在OS 10.10中使用Safari 8,並且我正在部署到LGG2和KitKat 4.4.2。

+1

我建議你減少你的問題,以重現該問題只需要在相關代碼/信息。有可能這樣做,你會發現你自己的問題。在任何情況下,加入了plunker /的jsfiddle幫助其他幫助您調試代碼。 – 2014-11-03 06:06:33

+0

我們有完全相同的問題。你最終做了什麼來解決這個問題?我們在想,也許我們應該停止使用自動增量,並創建自己的密鑰。 – Justin 2015-08-03 20:58:04

回答

0

在iOS9,許多IndexedDB的錯誤都是固定的,但不所有。我們目前正在iOS9 Beta 2上進行測試,並且您發現的這個特定錯誤並不是固定的。

我們可以不使用我們的對象存儲自動增量解決此問題。我們只需手動找到最大鍵值並增加它。

插入對象看起來是這樣的:

var store = db.transaction([entity], "readwrite").objectStore(entity); 
store.openCursor(null, "prev").onsuccess = function (event) { 
    var maxKey = event.target.result.key || 0; 
    object.id = maxKey + 1; 
    store.add(object); 
}