2014-09-24 17 views
29

Problem występuje, gdy masz dwa różne magazyny obiektów w tym samym indexeddb, wartości kluczy podstawowych wydają się być "udostępniane" we wszystkich sklepach.Podstawowy problem z kluczem w implementacji 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/)

W systemów iOS 8, jeśli podbiec na skrzypcach i kliknij "ADD1 dane do IndexedDB", a następnie 1000 wpisy dodane do "klientów" tabeli. Jeśli następnie klikniesz "Add2 data to IndexedDb", to 1000 wpisów zostanie dodanych do tabeli "dostawcy", ale 1000 z "klientów" zostanie usunięte.

Czy ktoś inny się z tym spotkał? Czy jest to część specyfikacji IndexedDb? Wygląda na to, że Chrome nie ma tego problemu.

EDYCJA: Znaleziono W3 Org IndexedDB Recommendation: "W danym magazynie obiektów nie może być wielu rekordów z tym samym kluczem." Wygląda na to, że Apple zastosował to na poziomie bazy danych.

+0

Wow, to jest źle. Nie testowałem jeszcze systemu iOS 8, ale otrzymałem od użytkowników raporty, że moja aplikacja oparta na iDB nie działa w ogóle w systemie iOS 8, co wyjaśniałoby to. Nie mogę powiedzieć, że jestem zaskoczony, pasuje to do mojej teorii konspiracji http://stackoverflow.com/a/20110477/786644 :) :) – dumbmatter

+1

Jeeze. Nawet jeśli pozwolisz mu określić wartość autoIncreement, wygląda na to, że jest uszkodzona. –

+1

Ugh. Próbowałem to naprawić za pomocą jednej transakcji - w jednej transakcji można określić N storestores. Nie, rzuca błąd. –

Odpowiedz

20

Mogę potwierdzić, że iOS8 jest zdecydowanie błędny. Próbowałem kilku obejść, ale najlepsze, co mogę zasugerować, to klucz podstawowy, który łączy jakiś unikatowy ciąg znaków, na przykład nazwę obiektu objectStore, z liczbą. Tak na przykład, biorąc pod uwagę dwa objectStores zwanych ludzi i notatki, chciałbym przechowywać dane z klawiszy tak:

ludzie/X notatki/X

X można ustawić ręcznie, albo użyć .count () w obiekcie objectStore, aby znaleźć licznik i dodać go. Oto przykład:

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

} 

Zauważ, że podałem keyPath "id" dla tego systemu operacyjnego.

+6

Zakładając, że iOS używa opartej na SQLite implementacji IndexedDB z kodem na https://github.com/WebKit/webkit/blob/master/Source/WebKit2/DatabaseProcess/IndexedDB/sqlite/UniqueIDBData_Base bazy danychSQLite. cpp, dane obiektów są przechowywane w tabeli "Rekordy" z polem "kluczowym" w SQLite DB. Kluczowe pole ma ograniczenie UNIQUE, a identyfikator sklepu nie jest częścią klucza. Whoops (!). Przypuszczam, że wpłynie to również na Safari w OS X 10.10. –

+2

Wygląda na to, że Apple sprawdził poprawkę kilka dni temu: https://github.com/WebKit/webkit/commit/daadc48666e5015e3b7f1ccba22588e6711a0706 – Lee

+0

Wygląda na to, że został naprawiony w iOS 9. Zobacz: https://gist.github.com/nolanlawson/08eb857c6b17a30c1b26 – Nux

1

Miałem podobny problem, jednak moja pierwsza wstawka do sklepu była małą tablicą z samą nazwą użytkownika i adresem e-mail, a drugi obiekt był bardzo duży z kilkoma zagnieżdżonymi tablicami danych.

Poniższa metoda wstawiania oddzwoni do wszystkich elementów, ale tylko drugi magazyn obiektów zostanie poprawnie zapisany w bazie danych.

Kiedy próbowałem cofnąć zamówienie, które zapisywałem do bazy danych (najpierw pisanie dużych obiektów magazynów przedmiotów i nazwy użytkownika/e-maili) obydwa magazyny zostały napisane poprawnie, ale klucze podstawowe zostały udostępnione między dwoma magazynami obiektów. Piloci Klucz główny: 1,2,3,4,5 AC Klucz główny: 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"); 

    }; 
} 
Powiązane problemy