核心数据异常:向实体添加新属性后出现 SQLite“没有这样的列”错误

Posted

技术标签:

【中文标题】核心数据异常:向实体添加新属性后出现 SQLite“没有这样的列”错误【英文标题】:Core Data exception: SQLite "no such column" error after adding a new attribute to an entity 【发布时间】:2019-01-26 21:35:20 【问题描述】:

将名为“localFilePath”的字符串属性添加到名为 GenericAttachment 的核心数据实体后,当我们尝试映射一组这些对象时,我们开始收到异常。

我们的几个实体与 GenericAttachment 的无序集合之间存在称为“附件”的一对多关系。

其中一个实体称为 InspectionMO。 GenericAttatchment 与 InspectionMO 有一对多的关系“inspection”(不是“inspections”,哎呀)。当我们获取 InspectionMO 的附件并尝试对其进行映射时,我们会得到以下异常:

NSInternalInconsistencyException
I/O error for database at /Users/justingarcia/Library/Developer/CoreSimulator/Devices/D075B44C-4F54-4703-8817-3DC4A6E7314E/data/Containers/Data/Application/F425E5AC-C215-4BE8-93DB-A3E6C48C83C4/Library/Application Support/Procore/Procore.  SQLite error code:1, 'no such column: t1.Z_55ATTACHMENTS5'

这是异常堆栈跟踪:

#0  0x000000010c94f705 in objc_exception_throw ()
#1  0x000000010e928f00 in -[NSSQLiteConnection prepareSQLStatement:] ()
#2  0x000000010ea99305 in -[NSSQLiteConnection selectRowsWithStatement:cached:] ()
#3  0x000000010e941d0b in newFetchedRowsForFetchPlan_MT ()
#4  0x000000010eb6e574 in _newFetchedPKsForRelationshipFaultRequest ()
#5  0x000000010eb6efba in _executeNewValuesForRelationshipFaultRequest ()
#6  0x000000010ead19a2 in -[NSSQLRelationshipFaultRequestContext executeRequestCore:] ()
#7  0x000000010eb40a00 in -[NSSQLStoreRequestContext executeRequestUsingConnection:] ()
#8  0x000000010eb14e5b in __52-[NSSQLDefaultConnectionManager handleStoreRequest:]_block_invoke ()
#9  0x000000011b25f602 in _dispatch_client_callout ()
#10 0x000000011b26d653 in _dispatch_lane_barrier_sync_invoke_and_complete ()
#11 0x000000010eb14d40 in -[NSSQLDefaultConnectionManager handleStoreRequest:] ()
#12 0x000000010eb1cbb4 in -[NSSQLCoreDispatchManager routeStoreRequest:] ()
#13 0x000000010ea61515 in -[NSSQLCore dispatchRequest:withRetries:] ()
#14 0x000000010ea5cdaa in -[NSSQLCore _newValuesForRelationship:forObjectWithID:withContext:error:] ()
#15 0x000000010e97a8cb in -[NSSQLCore newValueForRelationship:forObjectWithID:withContext:error:] ()
#16 0x000000010ea449d9 in __110-[NSPersistentStoreCoordinator(_NSInternalMethods) newValueForRelationship:forObjectWithID:withContext:error:]_block_invoke ()
#17 0x000000010ea39437 in -[NSPersistentStoreCoordinator _routeLightweightBlock:toStore:] ()
#18 0x000000010e97a7f7 in -[NSPersistentStoreCoordinator(_NSInternalMethods) newValueForRelationship:forObjectWithID:withContext:error:] ()
#19 0x000000010ea0b89e in __107-[NSManagedObjectContext(_NestedContextSupport) newValueForRelationship:forObjectWithID:withContext:error:]_block_invoke ()
#20 0x000000010e972108 in internalBlockToNSManagedObjectContextPerform ()
#21 0x000000011b25f602 in _dispatch_client_callout ()
#22 0x000000011b26d653 in _dispatch_lane_barrier_sync_invoke_and_complete ()
#23 0x000000010e972074 in _perform ()
#24 0x000000010e972c37 in -[NSManagedObjectContext(_NestedContextSupport) newValueForRelationship:forObjectWithID:withContext:error:] ()
#25 0x000000010e97a421 in -[NSFaultHandler retainedFulfillAggregateFaultForObject:andRelationship:withContext:] ()
#26 0x000000010e9a621e in -[_NSFaultingMutableSet willReadWithContents:] ()
#27 0x000000010e94e6a6 in -[_NSFaultingMutableSet count] ()
#28 0x000000011a9e9bdd in protocol witness for Collection.count.getter in conformance Set<A> ()
#29 0x000000011a8726d1 in Collection.map<A>(_:) ()
#30 0x00000001162ad07e in ObjectImportHelper.copyToMany<A>(_:to:cache:deleteMissing:onCopy:) at /Users/justingarcia/2/ios/Procore/Core/Utils/ObjectImportHelper+Relationships.swift:163
…

这里是一些核心数据记录:

CoreData: sql: SELECT 0, t0.Z_PK FROM Z_55INSPECTION t1 JOIN ZGENERICATTACHMENT t0 ON t0.Z_PK = t1.Z_55ATTACHMENTS5 WHERE t1.Z_70INSPECTION = ? 
2019-01-25 13:50:17.727987-0800 Procore[34877:10124838] [logging] no such column: t1.Z_55ATTACHMENTS5
CoreData: annotation: Disconnecting from sqlite database due to an error.
2019-01-25 13:50:17.748021-0800 Procore[34877:10124838] [error] error: (1) I/O error for database at /var/mobile/Containers/Data/Application/FFEB392B-302B-479E-98E8-008333FC2714/Library/Application Support/Procore/Procore.  SQLite error code:1, 'no such column: t1.Z_55ATTACHMENTS5'
CoreData: error: (1) I/O error for database at /var/mobile/Containers/Data/Application/FFEB392B-302B-479E-98E8-008333FC2714/Library/Application Support/Procore/Procore.  SQLite error code:1, 'no such column: t1.Z_55ATTACHMENTS5'
CoreData: annotation: total fetch execution time: 0.0207s for 0 rows.
2019-01-25 13:50:17.748727-0800 Procore[34877:10124838] [error] error: exception during newFetchedPKsForSourceID: I/O error for database at /var/mobile/Containers/Data/Application/FFEB392B-302B-479E-98E8-008333FC2714/Library/Application Support/Procore/Procore.  SQLite error code:1, 'no such column: t1.Z_55ATTACHMENTS5' with userInfo of 
    NSFilePath = "/var/mobile/Containers/Data/Application/FFEB392B-302B-479E-98E8-008333FC2714/Library/Application Support/Procore/Procore";
    NSSQLiteErrorDomain = 1;

我们正在使用 NSPersistentStoreDescription 的 shouldMigrateStoreAutomatically 和 shouldInferMappingModelAutomatically,我在日志中没有看到任何迁移错误(我们使用的是 -com.apple.CoreData.MigrationDebug 1)。

我们打开 SQLite 数据库文件,发现 Z_55INSPECTION 表在迁移到我们将 localFilePath 属性添加到 GenericAttachment 的新版本之前和之后都有一个名为 Z_55ATTACHMENTS6(不是 Z_55ATTACHMENTS5)的列。

那么,为什么 Core Data 会寻找名为 Z_55ATTACHMENTS5 而不是 Z_55ATTACHMENTS6 的列?

我们在谷歌搜索后发现了这两篇 Apple 邮件列表文章:a question 和 this follow-up 我认为这是说当多个实体具有相同名称的多对多关系时,列名末尾的数字会出现到另一个实体。在我们的例子中,我们有几个称为 GenericAttachment 的附件的多对多关系。但是我们并没有添加一个名为附件的新关系,我们只是在 GenericAttachment 中添加了一个属性。也许如果我们将所有这些关系重命名为唯一关系,问题就会消失?

【问题讨论】:

你能测试同样的事情不会发生在其他依赖于 GenericAttachment 的实体上吗?如果是,那么您的设置应该有问题。 【参考方案1】:

它选择该列,因为查询引用了Z_55INSPECTION.Z_55ATTACHMENTS5

SELECT 0, t0.Z_PK FROM Z_55INSPECTION t1

JOIN ZGENERICATTACHMENT t0 ON t0.Z_PK = t1.Z_55ATTACHMENTS5

WHERE t1.Z_70INSPECTION = ?

最简单的方法可能是将该列从 Z_55ATTACHMENTS6 重命名为 Z_55ATTACHMENTS5

...保留数据库的备份,以确保没有其他内容引用它。

【讨论】:

以上是关于核心数据异常:向实体添加新属性后出现 SQLite“没有这样的列”错误的主要内容,如果未能解决你的问题,请参考以下文章

为啥向核心数据实体添加双重属性会导致远距离相关实体中的属性冲突出现 NSInternalInconsistencyException?

向实体添加属性后快速核心数据崩溃

向核心数据实体添加属性

向核心数据实体添加瞬态属性是不是需要新版本模型?

使用 Sqlite3 向实体添加派生属性

应用轻量级迁移后,将 ios-add 列添加到 sqlite?