2014-09-24 12 views
29

Il problema è quando si hanno due diversi archivi di oggetti nello stesso indexeddb, i valori di chiave primaria sembrano "condivisi" tra tutti i negozi.Problema chiave primaria sull'implementazione iOS8 di 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/)

In iOS 8, se si esegue il violino e fare clic su "Dati Add1 a IndexedDB", di 1000 voci vengono aggiunti alla tabella "clienti". Se si fa clic su "Aggiungi dati a IndexedDb", quindi 1000 voci vengono aggiunte alla tabella "fornitori", ma viene rimosso il 1000 dai "clienti".

Qualcun altro ha incontrato questo? Questa parte della specifica IndexedDb? Chrome non sembra avere questo problema.

MODIFICA: trovato questo W3 Org IndexedDB Recommendation: "Non ci possono essere più record in un determinato archivio oggetti con la stessa chiave." Sembra che Apple abbia applicato questo a livello di database.

+0

Wow, questo è male. Non ho ancora provato iOS 8, ma ho ricevuto alcuni rapporti dagli utenti che la mia app basata su iDB non funziona affatto su iOS 8, e questo spiegherebbe. Non posso dire di essere sorpreso, si adatta alla mia teoria della cospirazione http://stackoverflow.com/a/20110477/786644 :) – dumbmatter

+1

Jeeze. Anche se lo si lascia specificare autoIncreement, sembra essere rotto. –

+1

Ugh. Ho provato a risolverlo usando una transazione: puoi specificare N oggetti in una transazione. No, genera un errore. –

risposta

20

Posso confermare che iOS8 è decisamente buggato qui. Ho provato qualche soluzione alternativa, ma il meglio che posso suggerire è una chiave primaria che combina alcune stringhe univoche, come il nome di objectStore, con un numero. Così, per esempio, dati due objectStores chiamati persone e le note, mi piacerebbe memorizzare i dati con i tasti in questo modo:

persone/X note/X

È possibile impostare X manualmente, oppure, utilizzare il .count () metodo su objectStore per trovare il conteggio e aggiungerne uno. Ecco un esempio:

//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"); 
    } 

} 

Nota che ho specificato keyPath di "id" per questo sistema operativo.

+6

Supponendo che iOS stia utilizzando l'implementazione basata su SQLite di IndexedDB con il codice all'indirizzo https://github.com/WebKit/webkit/blob/master/Source/WebKit2/DatabaseProcess/IndexedDB/sqlite/UniqueIDBDatabaseBackingStoreSQLite. cpp, i dati oggetto sono memorizzati in una tabella 'Record' con un campo 'chiave' in un DB SQLite. Il campo chiave ha un vincolo UNIQUE e l'ID negozio non fa parte della chiave. Whoops (!). Immagino che ciò influirà anche su Safari in OS X 10.10. –

+2

Sembra che Apple abbia controllato una correzione qualche giorno fa: https://github.com/WebKit/webkit/commit/daadc48666e5015e3b7f1ccba22588e6711a0706 – Lee

+0

Sembra che sia stato risolto in iOS 9. Vedi: https://gist.github.com/nolanlawson/08eb857c6b17a30c1b26 – Nux

1

Avevo un problema simile, tuttavia il mio primo inserimento nell'oggetttore era un piccolo array con solo username ed email e il secondo objecttore era molto grande con diversi array di dati annidati.

Il mio metodo di inserimento di seguito richiama correttamente tutte le voci, tuttavia solo il secondo archivio oggetti verrà scritto correttamente nel db.

Quando ho tentato di invertire l'ordine che stavo scrivendo nel database (scrivendo prima gli oggetti del grande oggetto e il nome utente/l'e-mail) entrambi gli oggetti sono stati scritti correttamente, tuttavia le chiavi primarie sono state condivise tra i due oggetti. piloti Chiave primaria: 1,2,3,4,5 AC Chiave primaria: 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"); 

    }; 
}