ios - 核心数据与父实体集一起保存

标签 ios sqlite core-data ios9

在我的应用程序中,我有一些可以存储一些可选数据的对象。有两种类型的此类对象 - 这样的对象应该是唯一的,而这样的对象不需要是唯一的。

那些唯一的具有附加属性 - uuid - 通过它检查唯一性。

非唯一的被调用,例如StoreObject和唯一的UniqueStoreObject。除了 uuid 属性外,它们完全相同。

因此,StoreObject 是没有父实体的实体。 UniqueStoreObject 是父实体设置为 StoreObject 的实体。正如我所说 - 两个实体描述的对象可以在一个后端同时满足。

但是,如果我尝试保存 NSManagedContext,其中我有 StoreObject 对象,我会从 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;
}

奇怪的是,这种行为并不稳定。如果它出现过一次 - 它将出现在下一次应用程序启动时。但是,例如,如果我删除唯一字段或其他一些实体(此处未提及两个),或重新创建其中一个实体(删除它并在 Xcode 托管模型工具中重新编写)它可能会消失。

找不到与字段可选性或托管对象工具中的唯一约束无关的关系。只有一件事我能捕捉到——这个 StoreObject 实体必须有子实体,并且在保存之前在上下文中直接实例化。

当我为没有属性并且是 StoreObject 实体的子实体的非唯一商店创建单独的实体时 - 问题就消失了

更新

在评论中要求提供代码示例。即使是最简单的情况也可能导致此错误

 //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 

更新 2

这是我使用 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'}

最佳答案

我认为有两个重叠的问题:主要问题是 uuid 的唯一性约束。我尝试创建一个与您自己的设置类似的设置,我可以重现错误的唯一情况是 uuid 具有唯一性约束

我从你的问题中注意到你不相信唯一性约束是牵连的,但我认为这是由于次要问题:最初我很困惑,因为我尝试应用唯一性约束是行不通的。而您的 SQLDebug 在构建数据库时显示了 uuid 的 UNIQUE 属性:

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 )

我的没有。在清理和一些实验之后,我终于让唯一性约束起作用(在上述意义上)。我一这样做,就开始遇到和你一样的错误:

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'

然后我尝试移除约束。

enter image description here

问题继续存在。即使我清理了构建,从模拟器中删除了应用程序并重新运行:还是出现了同样的问题。不知何故,即使数据模型编辑器没有显示对 uuid 的约束,一个正在被应用。我查看了隐藏在 xcdatamodeld 中的 XML,它就在那里:

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

很明显,Xcode 只是没有更新模型来反射(reflect)添加/删除的唯一性约束。但是,如果您对模型进行另一个更改(例如,添加和删除属性),则会对唯一性约束进行更改,uuid 的 UNIQUE 定义是创建表时应用,错误消失。

这与你自己的观察是一致的:

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.

您对模型中的其他实体或属性所做的更改会导致对唯一性约束的任何更改生效。

一旦您使用 Xcode 解决了这个问题,主要问题就会变得更加清晰:唯一性约束似乎对子实体不起作用

所有这些都是解释而不是解决方案。我猜是您的 UniqueStoreObject 子类的一些特定代码,而不是使用 CoreData 唯一性约束。我希望我有更好的解决方案,但我希望你能睡得好一点....

关于ios - 核心数据与父实体集一起保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35562052/

相关文章:

c# - 如何修复创建新页面时的此错误?

java - xerial sqlite-jdbc 3.7.2 在 OSX Mountain Lion 上返回 [SQLITE_NOTADB]

cocoa - KVO - 从存储中检索对象并显示版本时出现问题

ios - 使用核心数据

php - 如何在我的 in php 应用程序中修复来自 sqlite 的这些警告?

iOS 6 处理托管对象后台保存的标准方法是什么(2013 年)?

ios - 自动布局约束无法正常工作

推送/弹出第二个 View Controller 后,iOS UI 导致崩溃

ios - 使用 openUrl 从 TodayExtension 打开时如何调试 iOS App?

sql - 从每个类别中选择n个样本