2014-09-24 5 views
29

Проблема заключается в том, что у вас есть два разных хранилища объектов в одном и том же индексированном дБ, значения первичного ключа отображаются как «общие» для всех магазинов.Основная проблема ключа при реализации iOS8 IndexedDb

<body> 
    <script type="text/javascript"> 
     //prefixes of implementation that we want to test 
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; 

//prefixes of window.IDB objects 
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; 
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange 

if (!window.indexedDB) { 
    window.alert("Your browser doesn't support a stable version of IndexedDB.") 
} 


var db; 
var request = window.indexedDB.open("newDatabase", 4); 

request.onerror = function(event) { 
    console.log("error: "); 
}; 

request.onsuccess = function(event) { 
    db = request.result; 
    console.log("success: "+ db); 
}; 

request.onupgradeneeded = function(event) { 
     var db = event.target.result; 
     var objectStore = db.createObjectStore("customers", {keyPath: "arseid"}); 
    var objectStore = db.createObjectStore("test", {keyPath: "id"}); 
} 



function add1() { 
     var x = new Date(); 
    var h1 = x.getHours(); 
    var m1 = x.getMinutes(); 
    var s1 = x.getSeconds(); 
    console.log('starting insert on ' + h1 + ':' + m1 + ':' + s1); 

    var tx = db.transaction(["customers"], "readwrite"); 
    for (var i = 0; i < 1000; i++) { 
     var request = tx.objectStore("customers") 
       .put({ arseid: i, name: "Jonathan Smith", email: "[email protected]", favourite: "chocolate cake", pet: "rudolph the red nose reindeer", address: "999 letsbe avenue, townton, countyshire" }); 
    } 


    tx.oncomplete = function (e) { 
      // Re-render all the todo's 
      var x2 = new Date(); 
      var h2 = x2.getHours(); 
      var m2 = x2.getMinutes(); 
      var s2 = x2.getSeconds(); 
       console.log('transaction complete ' + h2 + ':' + m2 + ':' + s2); 
     } 
} 


function add2() { 
    //tx 2 
    var tx2 = db.transaction(["test"], "readwrite"); 
    for (var i = 0; i < 1000; i++) { 
     var request2 = tx2.objectStore("test") 
       .put({ id: i, name: "Robwin Mwengway", email: "[email protected]", favourite: "chocolate cake", pet: "rudolph the red nose reindeer", address: "999 letsbe avenue, townton, countyshire" }); 
    } 

    tx2.oncomplete = function (e) { 
      var x3 = new Date(); 
      var h3 = x3.getHours(); 
      var m3 = x3.getMinutes(); 
      var s3 = x3.getSeconds(); 
       console.log('transaction complete ' + h3 + ':' + m3 + ':' + s3); 
     } 
} 


    </script> 
<button onclick="add1()">Add1 data to indexedDb</button> 
<button onclick="add2()">Add2 data to indexedDb</button> 
</body> 

(Fiddle: http://jsfiddle.net/jonnyknowsbest/4pdp8vxe/)

В iOS8, если вы подбежали скрипку и нажмите кнопку "add1 данные в IndexedDB", то 1000 записей добавляются в таблицу "клиентов". Если вы затем щелкните «Add2 data to IndexedDb», то 1000 записей добавляются в таблицу «Поставщики», но 1000 из «клиентов» удаляется.

Есть ли у кого-нибудь еще такое? Является ли эта часть спецификации IndexedDb? У Chrome, похоже, нет этой проблемы.

EDIT: Найдено W3 Org IndexedDB Recommendation: «В данном хранилище объектов никогда не может быть нескольких записей с тем же ключом». Apple, похоже, применила это на уровне базы данных.

+0

Ого, это плохо. Я еще не пробовал iOS 8, но получил несколько отчетов от пользователей о том, что мое приложение на базе iDB вообще не запускается в iOS 8, и это объясняет это. Я не могу сказать, что я удивлен, он вписывается в мою теорию заговора http://stackoverflow.com/a/20110477/786644 :) – dumbmatter

+1

Jeeze. Даже если вы дадите ему указать autoIncreement, он, кажется, сломан. –

+1

Ugh. Я попытался исправить это, используя одну транзакцию - вы можете указать N объектов в одной транзакции. Нет, выдает ошибку. –

ответ

20

Я могу подтвердить, что iOS8 определенно неисправен здесь. Я пробовал несколько обходных решений, но лучшее, что я могу предложить, это первичный ключ, который объединяет некоторую уникальную строку, такую ​​как имя objectStore, с номером. Так, например, учитывая два objectStores называемых людьми и заметками, я бы хранить данные с ключами, как так:

людей/X примечания/X

Вы можете установить X вручную, или используйте .Count () на объектеStore, чтобы найти счетчик и добавить его. Вот пример:

//Define a person 
var person = { 
    name:"Ray", 
    created:new Date().toString(), 
} 

//Perform the add 
db.transaction(["people"],"readwrite").objectStore("people").count().onsuccess = function(event) { 
    var total = event.target.result; 
    console.log(total); 
    person.id = "person/" + (total+1); 

    var request = db.transaction(["people"],"readwrite").objectStore("people").add(person); 

    request.onerror = function(e) { 
     console.log("Error",e.target.error.name); 
     //some type of error handler 
    } 

    request.onsuccess = function(e) { 
     console.log("Woot! Did it"); 
    } 

} 

Обратите внимание, что я указал keyPath для «id» для этой ОС.

+6

Предполагая, что iOS использует SQLite-версию IndexedDB с кодом на странице https://github.com/WebKit/webkit/blob/master/Source/WebKit2/DatabaseProcess/IndexedDB/sqlite/UniqueIDBDatabaseBackingStoreSQLite. cpp, данные объекта хранятся в таблице «Записи» с полем «ключ» в SQLite DB. Поле ключа имеет ограничение UNIQUE, а идентификатор магазина не является частью ключа. Упс (!). Я предполагаю, что это повлияет и на Safari в OS X 10.10. –

+2

Похоже, что Apple проверила исправление несколько дней назад: https://github.com/WebKit/webkit/commit/daadc48666e5015e3b7f1ccba22588e6711a0706 – Lee

+0

Похоже, что это исправлено в iOS 9. См. Https://gist.github.com/nolanlawson/08eb857c6b17a30c1b26 – Nux

1

У меня была аналогичная проблема, однако моя первая вставка в объект-магазин была небольшим массивом с только именем пользователя и электронной почтой, а второй объект-хранилище был очень большим с несколькими вложенными массивами данных.

Мой метод вставки, приведенный ниже, приведет к успеху на всех элементах, однако только второй магазин объектов будет правильно записан в db.

Когда я попытался изменить порядок, который я писал в базу данных (сначала записывая объекты большого объекта магазина, а также имя пользователя/адрес электронной почты), оба объекта были написаны правильно, однако первичные ключи были разделены между двумя хранилищами объектов. пилотов Первичный ключ: 1,2,3,4,5 AC Первичный ключ: 6,7,8 ...

function insert_GroupRecord(Record, Store){ 
    //update individual sync record 
    var trans = dbGroup.transaction([Store],"readwrite"); 
    var store = trans.objectStore(Store); 
    var request = store.put(Record); 
    request.onsuccess = function(e){ 
     IOS_postMessage({Message:"SyncStatus", status:"Group_Insert "+Store}); 
    }; 
    request.onerror = function(e){ 
     GroupSyncERROR = true; 
     //IOS_postMessage({Message:"SyncStatus", status:"GroupSyncFail "+Store}); 
    }; 

    request.onupgradeneeded = function(evt){ 
     var objectStore = evt.currentTarget.result.createObjectStore("AC",{ keyPath: "id", autoIncrement: true }); 
     objectStore.createIndex("ident", "ident", { unique: true }); 
     var objectStore2 = evt.currentTarget.result.createObjectStore("Pilots",{ keyPath: "id", autoIncrement: true }); 
     objectStore2.createIndex("chatname", "chatname", { unique: true }); 
     console.log("KFM_Group Upgrade Completed"); 

    }; 
} 
Смежные вопросы