2014-09-24 5 views
29

Das Problem ist, wenn Sie zwei verschiedene Objekt speichert in der gleichen indexeddb, Primärschlüssel Werte scheinen über alle Stores "freigegeben".Primärschlüssel Problem bei iOS8-Implementierung von 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: "jonathan.[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 iOS8, wenn Sie die Geige laufen auf und klicken Sie auf "Add1 Daten IndexedDB", dann 1000 Einträge in die "Kunden" -Tabelle hinzugefügt bekommen. Wenn Sie dann auf "Add2 data to IndexedDb" klicken, werden 1000 Einträge zur Tabelle "Lieferanten" hinzugefügt, aber die 1000 von den "Kunden" wird entfernt.

Hat sonst noch jemand das gefunden? Ist das ein Teil der IndexedDb-Spezifikation? Chrome scheint dieses Problem nicht zu haben.

EDIT: Gefunden W3 Org IndexedDB Recommendation: "Es kann nie mehrere Datensätze in einem bestimmten Objekt speichern mit dem gleichen Schlüssel." Apple scheint dies auf Datenbankebene angewendet zu haben.

+0

Wow, das ist schlecht. Ich habe iOS 8 noch nicht ausprobiert, aber ich habe Berichte von Nutzern bekommen, dass meine iDB-basierte App überhaupt nicht in iOS 8 läuft, und das würde es erklären. Ich kann nicht sagen, dass ich überrascht bin, es passt in meine Verschwörungstheorie http://stackoverflow.com/a/20110477/786644 :) – dumbmatter

+1

Jeeze. Selbst wenn Sie autoInCreement angeben, scheint es defekt zu sein. –

+1

Ugh. Ich habe versucht, es mit einer einzigen Transaktion zu beheben - Sie können N Objektspeicher in einer Transaktion angeben. Nein, es wird ein Fehler ausgegeben. –

Antwort

20

Ich kann bestätigen, dass iOS8 hier definitiv fehlerhaft ist. Ich habe ein paar Workarounds versucht, aber das Beste, was ich vorschlagen kann, ist ein Primärschlüssel, der eine eindeutige Zeichenfolge wie den Namen des Objektspeichers mit einer Zahl kombiniert. So zum Beispiel bei zwei objectStores Menschen und Notizen genannt, würde ich wie so Daten mit Schlüsseln speichern:

Personen/X Noten/X

Sie X manuell einstellen können, oder verwenden Sie die .count () Methode auf dem Objektspeicher, um die Anzahl zu finden und einen zu addieren. Hier ein Beispiel:

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

} 

Beachten Sie, dass ich keyPath von "ID" für dieses Betriebssystem angegeben.

+6

Angenommen, iOS verwendet die SQLite-basierte Implementierung von IndexedDB mit dem Code unter https://github.com/WebKit/webkit/blob/master/Source/WebKit2/DatabaseProcess/IndexedDB/sqlite/UniqueIDBDatabaseBackingStoreSQLite. cpp, Objektdaten werden in einer 'Records' Tabelle mit einem 'key' Feld in einer SQLite DB gespeichert. Das Schlüsselfeld hat eine UNIQUE-Einschränkung und die Geschäfts-ID ist nicht Teil des Schlüssels. Whoops (!). Ich vermute, dass dies auch Safari in OS X 10.10 betreffen würde. –

+2

Sieht so aus, als hätte Apple vor ein paar Tagen eine Überprüfung vorgenommen: https://github.com/WebKit/webkit/commit/daadc48666e5015e3b7f1ccba22588e6711a0706 – Lee

+0

Scheint so, als wäre es in iOS 9 behoben. Siehe: https://gist.github.com/nolanlawson/08eb857c6b17a30c1b26 – Nux

1

Ich hatte ein ähnliches Problem, aber meine erste Einfügung in den Objektspeicher war ein kleines Array mit nur Benutzername und E-Mail und der zweite Objektspeicher war sehr groß mit mehreren verschachtelten Datenfeldern.

Meine Einfügemethode unten würde den Erfolg auf allen Elementen zurückrufen, aber nur der zweite Objektspeicher würde korrekt in die db geschrieben werden.

Als ich versuchte, die Reihenfolge umzukehren, die ich in die Datenbank schrieb (die großen Objektspeicherelemente zuerst und den Benutzernamen/die E-Mail schreiben), wurden beide Objektspeicher korrekt geschrieben, aber die Primärschlüssel wurden zwischen den beiden Objektspeichern geteilt. Piloten Primary Key: 1,2,3,4,5 AC Primärschlüssel: 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"); 

    }; 
}