问题: 当我获取一个在同一上下文中更新了关系的实体时,获取请求返回一个 nil。
说明:
数据模式:联系人<--->费用(一对多关系)联系人的“serverId”属性是唯一的,并且由于一些附加规则,我不能在核心数据中使用“约束”,而是使用以下代码。
现在,当从网络响应中插入一系列费用时,我对同一个联系人有多项费用。以下代码返回 nil,即使联系人存在于同一上下文中,如果它有更新。
if let entity = Contact.fetch(serverId: serverId, context: context) {
return entity
} else {
return Contact.new(serverId: serverId, context: context)
}
以下是支持的调试器日志:
(lldb) po serverId
55001
(lldb) po Contact.fetch(serverId: serverId, context: context)
nil
(lldb) po context.updatedObjects.filter { ($0 as? Entity)?.serverId == serverId }.count
1
(lldb) po context.updatedObjects.filter { ($0 as? Entity)?.serverId == serverId }.first?.changedValues().keys
▿ Optional<Keys>
▿ some : Dictionary.Keys(["expenses"])
▿ _variant : _Variant
▿ object : _BridgeStorage<__RawDictionaryStorage>
- rawValue : (Opaque Value)
(lldb) po context.reset()
0 elements
(lldb) po Contact.fetch(serverId: serverId, context: context)
▿ Optional<Contact>
- some : <Contact: 0x6000015371b0> (entity: Contact; id: 0xe7984dad6d91badc <x-coredata://593D407B-BF00-4923-980E-FDC7BEBD46C1/Contact/p834>; data: <fault>)
添加了其他详细信息:
实体只是一个协议包装器,下面是一个简化的代码。
protocol Entity {
var serverId: Int64 { get set }
}
extension Contact: Entity {}
获取实现,重用多个“实体”类型。
extension Entity {
static func fetch(serverId: Int64, context: NSManagedObjectContext) -> Entity? {
let predicate = NSPredicate(format: "serverId == '\(String(serverId))'")
return context.fetch(Entity.self, predicate: predicate)?.first
}
func fetch<T: NSManagedObject>(_ type: T.Type, predicate: NSPredicate?, sort: [NSSortDescriptor]? = nil) -> [T]? {
let context = self
let request = T.fetchRequest()
if let predicate = predicate {
request.predicate = predicate
}
if let sortDescriptors = sort {
request.sortDescriptors = sortDescriptors
}
var results: [NSFetchRequestResult] = []
do {
results = try context.fetch(request)
} catch {
print("Error with request: \(error)")
}
return results as? [T] ?? []
}
Temp Fix:通过检查当前上下文中的对象添加
if entity == nil, context.hasChanges == true {
entity = context.updatedObjects.first { ($0 as? Entity)?.serverId == serverId } as? Entity
if entity == nil {
entity = context.insertedObjects.first { ($0 as? Entity)?.serverId == serverId } as? Entity
}
}
(lldb) po context.updatedObjects.filter { ($0 as? Entity)?.serverId == serverId }.count
1
(lldb) po context.updatedObjects.filter { ($0 as? Entity)?.serverId == serverId }.first?.changedValues().keys
▿ Optional<Keys>
▿ some :(["expenses"])
▿ _variant : _Variant
▿ object : _BridgeStorage<__RawDictionaryStorage>
- rawValue : (Opaque Value)