Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data save with parent entity set

In my application I have objects that can store some optional data. There're two types of such objects - such, that should be unique and such, that don't need to be unique.

Those, that are unique has additional attribute - uuid - by which uniqueness is checked.

Non-unique are called, for instance StoreObject and unique UniqueStoreObject. Except for that uuid attribute they are completely same.

So, StoreObject is entity with no parent entity. UniqueStoreObject is entity with parent entity set to StoreObject. As I said - objects described by both entities can be met simultaneously in one backend.

But, if I try to save NSManagedContext, in which I have StoreObject objects, I get save error log messages from 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;
}

To make stranger, this behaviour isn't stable. If it appeared once - it will appear on next application launches. But, if I, for example, delete uniquing field, or some other Entity (not two mentioned here), or recreate one of those entities (delete it and write anew in Xcode managed model tool) it can disappear.

Couldn't find no relation to Optionality of fields, or unique constraints in managed object tool. Only one thing I could catch - this StoreObject entity must have child entity and be directly instantiated in context before save.

When I created separate entity for non-unique stores that have no attributes and is child of StoreObject entity - problem just vanished

Update

In comments have been asked for code example. Even the simplest situation can cause this 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

Here is what I get with SQLDebug argument 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'}
like image 489
Sergii Martynenko Jr Avatar asked Sep 25 '22 07:09

Sergii Martynenko Jr


1 Answers

I think there are two overlapping problems: the primary problem being the uniqueness constraint on uuid. I tried creating a similar set-up to your own, and the only situation in which I could reproduce the error was if uuid had a uniqueness constraint.

I note from your question that you do not believe the uniqueness constraint is implicated, but I think this is due to the secondary problem: initially I was perplexed because my attempt to apply a uniqueness constraint would not work. Whereas your SQLDebug showed a UNIQUE attribute for uuid when the database was built:

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 )

mine did not. After cleaning, and a bit of experimentation, I finally got the uniqueness constraint to work (in the above sense). As soon as I did, I started to suffer the same error as you:

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'

I then tried removing the constraint.

enter image description here

And the problem continued. Even if I cleaned the build, deleted the app from the simulator and reran: the same problem occurred. Somehow, even though the data model editor showed no constraint on uuid, one was being applied. I looked at the XML tucked away inside the xcdatamodeld, and there it was:

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

Plainly Xcode just isn't updating the model to reflect added/deleted uniqueness constraints. However, if you make another change to the model (add and remove an attribute, for example), the change to the uniqueness constraints is made, the UNIQUE definition for uuid is applied when the tables are created, and the error disappears.

This is consistent with your own observations:

But, if I, for example, delete uniquing field, or some other Entity (not two mentioned here), or recreate one of those entities (delete it and write anew in Xcode managed model tool) it can disappear.

The changes you make to the other entities or attributes in the model cause any changes to the uniqueness constraints to take effect.

Once you work around this problem with Xcode, the main problem becomes clearer: Uniqueness constraints just don't seem to work for subentities.

All of which is an explanation rather than a solution. I guess some specific code for your UniqueStoreObject subclass, rather than using the CoreData uniqueness constraints. I wish I had a better solution, but I hope you can sleep a little better....

like image 68
pbasdf Avatar answered Sep 29 '22 06:09

pbasdf