2016-02-22 17 views
5

Nella mia applicazione sono presenti oggetti che possono contenere alcuni dati opzionali. Ci sono due tipi di tali oggetti - tali, che dovrebbero essere unici e tali, che non hanno bisogno di essere unici.Dati principali salvati con set di entità padre

Questi, che sono unici, hanno attributo aggiuntivo - uuid - con cui viene controllata l'univocità.

Non univoco vengono chiamati, ad esempio StoreObject e UniqueStoreObject univoco. Tranne che per l'attributo uuid, sono completamente uguali.

Quindi, StoreObject è un'entità senza entità padre. UniqueStoreObject è un'entità con entità padre impostata su StoreObject. Come ho detto, gli oggetti descritti da entrambe le entità possono essere incontrati simultaneamente in un back-end.

Ma, se provo a conservare NSManagedContext, in cui ho oggetti storeObject, ottengo salvare i messaggi di log di errore da Core Data -

CoreData: error: (1) I/O error for database at *path to base*/MapStorageTest.sqlite. SQLite error code:1, 'near "WHERE": syntax error' 
Core Data: error: -executeRequest: encountered exception = I/O error for database at *path to base*/MapStorageTest.sqlite. SQLite error code:1, 'near "WHERE": syntax error' with userInfo = { 
NSFilePath = "*path to base*/MapStorageTest.sqlite"; 
NSSQLiteErrorDomain = 1; 
} 

Per rendere estraneo, questo comportamento non è stabile. Se appare una volta, apparirà al prossimo avvio dell'applicazione. Ma, se io, ad esempio, elimini un campo uniquing, o qualche altra Entità (non due menzionata qui), o ricrea una di quelle entità (cancellala e scriverla di nuovo nello strumento del modello gestito Xcode) può sparire.

Impossibile trovare alcuna relazione a Optionalità dei campi o vincoli univoci nello strumento oggetto gestito. Solo una cosa che potrei prendere: questa entità StoreObject deve avere un'entità figlio e essere istanziata direttamente nel contesto prima del salvataggio.

Quando ho creato un'entità separata per gli archivi non unici che non hanno attributi ed è figlio di storeObject entità - problema semplicemente svanito

Aggiornamento

Nei commenti è stato chiesto per esempio di codice. Anche la situazione più semplice può causare questo bug

//Everything happens in viewDidLoad method 

//Context is created by Xcode-genereate code. It has main queue concurency type 
NSManagedObjectContext *ctx = [(AppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext]; 
NSManagedObject *storeObject = [NSEntityDescription insertNewObjectForEntityForName:@"StoreObject" 
                  inManagedObjectContext:ctx]; 
[ctx save:&err]; //Here I get those error messages and error object is returned 

Update 2

Ecco che cosa ottengo con argomento SQLDebug 1

2016-02-25 22:59:05.438 ParentEntityCheck[31701:11387091] CoreData: annotation: Connecting to sqlite database file at "*path to base*/ParentEntityCheck.sqlite" 
2016-02-25 22:59:05.441 ParentEntityCheck[31701:11387091] CoreData: annotation: creating schema. 
2016-02-25 22:59:05.441 ParentEntityCheck[31701:11387091] CoreData: sql: pragma page_size=4096 
2016-02-25 22:59:05.441 ParentEntityCheck[31701:11387091] CoreData: sql: pragma auto_vacuum=2 
2016-02-25 22:59:05.445 ParentEntityCheck[31701:11387091] CoreData: sql: BEGIN EXCLUSIVE 
2016-02-25 22:59:05.445 ParentEntityCheck[31701:11387091] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA' 
2016-02-25 22:59:05.446 ParentEntityCheck[31701:11387091] CoreData: sql: CREATE TABLE ZSTOREOBJECT (Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZLASTLOAD TIMESTAMP, ZSTORECAPACITY VARCHAR, ZSTORENAME VARCHAR, ZUUID VARCHAR UNIQUE) 
2016-02-25 22:59:05.447 ParentEntityCheck[31701:11387091] CoreData: sql: CREATE INDEX IF NOT EXISTS ZSTOREOBJECT_Z_ENT_INDEX ON ZSTOREOBJECT (Z_ENT) 
2016-02-25 22:59:05.447 ParentEntityCheck[31701:11387091] CoreData: annotation: Creating primary key table. 
2016-02-25 22:59:05.448 ParentEntityCheck[31701:11387091] CoreData: sql: CREATE TABLE Z_PRIMARYKEY (Z_ENT INTEGER PRIMARY KEY, Z_NAME VARCHAR, Z_SUPER INTEGER, Z_MAX INTEGER) 
2016-02-25 22:59:05.448 ParentEntityCheck[31701:11387091] CoreData: sql: INSERT INTO Z_PRIMARYKEY(Z_ENT, Z_NAME, Z_SUPER, Z_MAX) VALUES(1, 'StoreObject', 0, 0) 
2016-02-25 22:59:05.449 ParentEntityCheck[31701:11387091] CoreData: sql: INSERT INTO Z_PRIMARYKEY(Z_ENT, Z_NAME, Z_SUPER, Z_MAX) VALUES(2, 'UniqueStoreObject', 1, 0) 
2016-02-25 22:59:05.449 ParentEntityCheck[31701:11387091] CoreData: sql: CREATE TABLE Z_METADATA (Z_VERSION INTEGER PRIMARY KEY, Z_UUID VARCHAR(255), Z_PLIST BLOB) 
2016-02-25 22:59:05.450 ParentEntityCheck[31701:11387091] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA' 
2016-02-25 22:59:05.450 ParentEntityCheck[31701:11387091] CoreData: sql: DELETE FROM Z_METADATA WHERE Z_VERSION = ? 
2016-02-25 22:59:05.450 ParentEntityCheck[31701:11387091] CoreData: sql: INSERT INTO Z_METADATA (Z_VERSION, Z_UUID, Z_PLIST) VALUES (?, ?, ?) 
2016-02-25 22:59:05.451 ParentEntityCheck[31701:11387091] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_MODELCACHE' 
2016-02-25 22:59:05.451 ParentEntityCheck[31701:11387091] CoreData: sql: CREATE TABLE Z_MODELCACHE (Z_CONTENT BLOB) 
2016-02-25 22:59:05.454 ParentEntityCheck[31701:11387091] CoreData: sql: INSERT INTO Z_MODELCACHE (Z_CONTENT) VALUES (?) 
2016-02-25 22:59:05.454 ParentEntityCheck[31701:11387091] CoreData: sql: COMMIT 
2016-02-25 22:59:05.455 ParentEntityCheck[31701:11387091] CoreData: sql: pragma journal_mode=wal 
2016-02-25 22:59:05.457 ParentEntityCheck[31701:11387091] CoreData: sql: pragma journal_mode=wal 
2016-02-25 22:59:05.457 ParentEntityCheck[31701:11387091] CoreData: sql: pragma cache_size=200 
2016-02-25 22:59:05.458 ParentEntityCheck[31701:11387091] CoreData: sql: SELECT Z_VERSION, Z_UUID, Z_PLIST FROM Z_METADATA 
2016-02-25 22:59:05.459 ParentEntityCheck[31701:11387091] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_MODELCACHE' 
2016-02-25 22:59:05.462 ParentEntityCheck[31701:11387091] CoreData: sql: BEGIN EXCLUSIVE 
2016-02-25 22:59:05.463 ParentEntityCheck[31701:11387091] CoreData: sql: SELECT Z_MAX FROM Z_PRIMARYKEY WHERE Z_ENT = ? 
2016-02-25 22:59:05.463 ParentEntityCheck[31701:11387091] CoreData: sql: UPDATE Z_PRIMARYKEY SET Z_MAX = ? WHERE Z_ENT = ? AND Z_MAX = ? 
2016-02-25 22:59:05.464 ParentEntityCheck[31701:11387091] CoreData: sql: COMMIT 
2016-02-25 22:59:05.465 ParentEntityCheck[31701:11387091] CoreData: sql: BEGIN EXCLUSIVE 
2016-02-25 22:59:05.466 ParentEntityCheck[31701:11387091] CoreData: sql: INSERT INTO ZSTOREOBJECT(Z_PK, Z_ENT, Z_OPT, ZLASTLOAD, ZSTORECAPACITY, ZSTORENAME) VALUES(?, ?, ?, ?, ?, ?) 
2016-02-25 22:59:05.467 ParentEntityCheck[31701:11387091] CoreData: sql: UPDATE ZSTOREOBJECT SET WHERE Z_PK = ? 
2016-02-25 22:59:05.467 ParentEntityCheck[31701:11387091] CoreData: annotation: Disconnecting from sqlite database due to an error. 
2016-02-25 22:59:05.469 ParentEntityCheck[31701:11387091] CoreData: error: (1) I/O error for database at *path to base*/ParentEntityCheck.sqlite. SQLite error code:1, 'near "WHERE": syntax error' 
2016-02-25 22:59:05.470 ParentEntityCheck[31701:11387091] Core Data: error: -executeRequest: encountered exception = I/O error for database at *path to base*/ParentEntityCheck.sqlite. SQLite error code:1, 'near "WHERE": syntax error' with userInfo = { 
    NSFilePath = "*path to base*/ParentEntityCheck.sqlite"; 
    NSSQLiteErrorDomain = 1; 
} 
2016-02-25 22:59:05.471 ParentEntityCheck[31701:11387091] CoreData: annotation: Connecting to sqlite database file at "*path to base*/ParentEntityCheck.sqlite" 
2016-02-25 22:59:05.471 ParentEntityCheck[31701:11387091] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA' 
2016-02-25 22:59:05.473 ParentEntityCheck[31701:11387091] CoreData: sql: pragma journal_mode=wal 
2016-02-25 22:59:05.473 ParentEntityCheck[31701:11387091] CoreData: sql: pragma cache_size=200 
2016-02-25 22:59:05.474 ParentEntityCheck[31701:11387091] CoreData: sql: BEGIN EXCLUSIVE 
2016-02-25 22:59:05.474 ParentEntityCheck[31701:11387091] CoreData: sql: INSERT INTO ZSTOREOBJECT(Z_PK, Z_ENT, Z_OPT, ZLASTLOAD, ZSTORECAPACITY, ZSTORENAME) VALUES(?, ?, ?, ?, ?, ?) 
2016-02-25 22:59:05.475 ParentEntityCheck[31701:11387091] CoreData: sql: UPDATE ZSTOREOBJECT SET WHERE Z_PK = ? 
2016-02-25 22:59:05.475 ParentEntityCheck[31701:11387091] CoreData: annotation: Disconnecting from sqlite database due to an error. 
2016-02-25 22:59:05.477 ParentEntityCheck[31701:11387091] CoreData: error: (1) I/O error for database at *path to base*/ParentEntityCheck.sqlite. SQLite error code:1, 'near "WHERE": syntax error' 
2016-02-25 22:59:05.477 ParentEntityCheck[31701:11387091] Core Data: error: -executeRequest: encountered exception = I/O error for database at *path to base*/ParentEntityCheck.sqlite. SQLite error code:1, 'near "WHERE": syntax error' with userInfo = { 
    NSFilePath = "*path to base*/ParentEntityCheck.sqlite"; 
    NSSQLiteErrorDomain = 1; 
} 
2016-02-25 22:59:05.488 ParentEntityCheck[31701:11387091] CoreData: annotation: Connecting to sqlite database file at "*path to base*/ParentEntityCheck.sqlite" 
2016-02-25 22:59:05.489 ParentEntityCheck[31701:11387091] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA' 
2016-02-25 22:59:05.491 ParentEntityCheck[31701:11387091] CoreData: sql: pragma journal_mode=wal 
2016-02-25 22:59:05.491 ParentEntityCheck[31701:11387091] CoreData: sql: pragma cache_size=200 
2016-02-25 22:59:05.491 ParentEntityCheck[31701:11387091] CoreData: sql: BEGIN EXCLUSIVE 
2016-02-25 22:59:05.492 ParentEntityCheck[31701:11387091] CoreData: sql: INSERT INTO ZSTOREOBJECT(Z_PK, Z_ENT, Z_OPT, ZLASTLOAD, ZSTORECAPACITY, ZSTORENAME) VALUES(?, ?, ?, ?, ?, ?) 
2016-02-25 22:59:05.492 ParentEntityCheck[31701:11387091] CoreData: sql: UPDATE ZSTOREOBJECT SET WHERE Z_PK = ? 
2016-02-25 22:59:05.493 ParentEntityCheck[31701:11387091] CoreData: annotation: Disconnecting from sqlite database due to an error. 
2016-02-25 22:59:05.495 ParentEntityCheck[31701:11387091] CoreData: error: (1) I/O error for database at *path to base*/ParentEntityCheck.sqlite. SQLite error code:1, 'near "WHERE": syntax error' 
2016-02-25 22:59:05.496 ParentEntityCheck[31701:11387091] Core Data: error: -executeRequest: encountered exception = I/O error for database at *path to base*/ParentEntityCheck.sqlite. SQLite error code:1, 'near "WHERE": syntax error' with userInfo = { 
    NSFilePath = "*path to base*/ParentEntityCheck.sqlite"; 
    NSSQLiteErrorDomain = 1; 
} 
2016-02-25 22:59:05.560 ParentEntityCheck[31701:11387091] CoreData: annotation: Connecting to sqlite database file at "*path to base*/ParentEntityCheck.sqlite" 
2016-02-25 22:59:05.561 ParentEntityCheck[31701:11387091] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA' 
2016-02-25 22:59:05.562 ParentEntityCheck[31701:11387091] CoreData: sql: pragma journal_mode=wal 
2016-02-25 22:59:05.562 ParentEntityCheck[31701:11387091] CoreData: sql: pragma cache_size=200 
2016-02-25 22:59:05.562 ParentEntityCheck[31701:11387091] CoreData: sql: BEGIN EXCLUSIVE 
2016-02-25 22:59:05.563 ParentEntityCheck[31701:11387091] CoreData: sql: INSERT INTO ZSTOREOBJECT(Z_PK, Z_ENT, Z_OPT, ZLASTLOAD, ZSTORECAPACITY, ZSTORENAME) VALUES(?, ?, ?, ?, ?, ?) 
2016-02-25 22:59:05.600 ParentEntityCheck[31701:11387091] CoreData: sql: UPDATE ZSTOREOBJECT SET WHERE Z_PK = ? 
2016-02-25 22:59:05.601 ParentEntityCheck[31701:11387091] CoreData: annotation: Disconnecting from sqlite database due to an error. 
2016-02-25 22:59:05.602 ParentEntityCheck[31701:11387091] CoreData: error: (1) I/O error for database at *path to base*/ParentEntityCheck.sqlite. SQLite error code:1, 'near "WHERE": syntax error' 
2016-02-25 22:59:05.683 ParentEntityCheck[31701:11387091] Error saving ctx Error Domain=NSCocoaErrorDomain Code=256 "The file “ParentEntityCheck.sqlite” couldn’t be opened." UserInfo={NSFilePath=*path to base*/ParentEntityCheck.sqlite, NSSQLiteErrorDomain=1, NSUnderlyingException=I/O error for database at *path to base*/ParentEntityCheck.sqlite. SQLite error code:1, 'near "WHERE": syntax error'} 
+0

L'ereditarietà delle entità dovrebbe "funzionare". Non ci sono requisiti speciali. Come con qualsiasi altra istanza, i tuoi dati devono passare tutte le regole di convalida che hai, ma il gioco è fatto. Da quello che hai descritto non c'è una ragione ovvia per cui fallirebbe, quindi sarebbe di grande aiuto se potessi includere del codice che illustri cosa sta realmente accadendo. –

+0

Le entità astratte non possono essere istanziate direttamente. – quellish

+0

@quellish Come ho detto - StoreObject non è un'entità astratta –

risposta

2

Penso che ci siano due problemi che si sovrappongono: il problema principale essendo il vincolo di unicità su uuid. Ho provato a creare un setup simile al tuo, e l'unica situazione in cui potevo riprodurre l'errore era se uuid aveva un vincolo di unicità.

Ho notato dalla tua domanda che non credi che il vincolo di unicità sia implicato, ma penso che questo sia dovuto al problema secondario: inizialmente ero perplesso perché il mio tentativo di applicare un vincolo di unicità non funzionava. Mentre il vostro SQLDebug ha mostrato un attributo univoco per uuid quando il database è stato costruito:

CoreData: sql: CREATE TABLE ZSTOREOBJECT (Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZLASTLOAD TIMESTAMP, ZSTORECAPACITY VARCHAR, ZSTORENAME VARCHAR, ZUUID VARCHAR UNIQUE) 

mio non ha fatto. Dopo la pulizia e un po 'di sperimentazione, ho finalmente ottenuto il vincolo di unicità al lavoro (nel senso precedente).Appena ho fatto, ho iniziato a subire lo stesso errore come te:

CoreData: sql: UPDATE ZSTOREOBJECT SET WHERE Z_PK = ? 
CoreData: annotation: Disconnecting from sqlite database due to an error. 
CoreData: error: (1) I/O error for database at *path to base*/ParentEntityCheck.sqlite. SQLite error code:1, 'near "WHERE": syntax error' 

Ho quindi provato a rimuovere il vincolo.

enter image description here

E il problema ha continuato. Anche se ho pulito la build, ho cancellato l'app dal simulatore e reran: si è verificato lo stesso problema. In qualche modo, anche se l'editor del modello di dati non mostrava alcun vincolo su uuid, ne veniva applicato uno. Ho guardato il XML nascosto all'interno del xcdatamodeld, ed era lì:

<entity name="UniqueStoreObject" representedClassName="UniqueStoreObject" parentEntity="StoreObject" syncable="YES"> 
    <attribute name="uuid" attributeType="String" syncable="YES"/> 
    <uniquenessConstraints> 
     <uniquenessConstraint> 
      <constraint value="uuid"/> 
     </uniquenessConstraint> 
    </uniquenessConstraints> 
</entity> 

Chiaramente Xcode semplicemente non è l'aggiornamento del modello in modo da riflettere aggiunto/eliminato vincoli di unicità. Tuttavia, se si effettua un'altra modifica nel modello (aggiungere e rimuovere un attributo, ad esempio), viene apportata la modifica ai vincoli di unicità, la definizione UNICA per uuid viene applicata quando le tabelle vengono create e l'errore scompare.

Ciò è coerente con le vostre osservazioni:

Ma, se, per esempio, eliminare campo uniquing, o qualche altra entità (non due menzionati qui), o ricreare una di quelle entità (eliminarlo e scrivere di nuovo nello strumento del modello gestito Xcode) può scomparire.

Le modifiche apportate alle altre entità o attributi nel modello fanno sì che eventuali modifiche ai vincoli di unicità abbiano effetto.

Una volta risolto questo problema con Xcode, il problema principale diventa più chiaro: I vincoli di unicità non sembrano funzionare per le sottenticità.

Tutto ciò è una spiegazione piuttosto che una soluzione. Immagino un codice specifico per la sottoclasse UniqueStoreObject, anziché utilizzare i vincoli di unicità di CoreData. Vorrei avere una soluzione migliore, ma spero che tu possa dormire un po 'meglio ....

+0

Immagino, ora riesco a dormire meglio. La tua risposta è ciò che stavo cercando. La soluzione che ho trovato - crea una sottoentità NonuniqueStoreObject senza ulteriori proprietà e crea un'istanza al posto di StoreObject. In questo caso, tutto funziona bene –

Problemi correlati