核心数据插入验证(validateForInsert)是否触发得太早?

时间:2019-03-29 10:22:29

标签: ios swift xcode validation core-data

我正在尝试将核心数据中的验证设置为简单的托管对象结构。

两者之间存在BuildingFloor,并且两者之间是一对多的关系(在建筑物上有很多楼层)。

Floor中的验证器看起来像这样

// extension of auto generated managed object (Floor)
extension Floor {
    override public func validateForInsert() throws {
        try super.validateForInsert()
        if (self.building == nil) {
            throw ValidationError.missingBuilding("a floor requires a building")
        }
    }
}

还有我简单的测试经理:

import Foundation
import CoreData

class ObjectNodeManager {

    let persistentContainer: NSPersistentContainer!

    init(container: NSPersistentContainer) {
        self.persistentContainer = container
        self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
    }

    lazy var backgroundContext: NSManagedObjectContext = {
        return self.persistentContainer.newBackgroundContext()
    }()

    func insertObjectNode(objectNode: ObjectNode) -> ObjectNode? {
        backgroundContext.insert(objectNode)
        return objectNode
    }

    func save() {
        if backgroundContext.hasChanges {
            do {
                try backgroundContext.save()
            } catch {
                fatalError("save error \(error)")
            }
        }
    }
}

当我尝试创建新建筑物和地板的保存时,出现异常。

let building = Building(context: manager.backgroundContext)
let floor = Floor(context: manager.backgroundContext)
floor.building = building // VALIDATION EXCEPTION!

// a basic backgroundContext.save() (persistentContainer) in the manager
manager.save()

对于validationForInsert,我无法插入/保存托管对象。另外,我可以使用validationForUpdate,但是为时已晚,因为我不想存储没有与Floor有适当关系的Building

有人建议如何保存具有所需关系并在插入时进行验证的管理对象?

谢谢。

2 个答案:

答案 0 :(得分:1)

manager.background上下文始终返回新的上下文,您的buildingfloor存在于两个不同的上下文中。

let backgroundContext = manager.backgroundContext
let building = Building(context: backgroundContext)
let floor = Floor(context: backgroundContext)
floor.building = building
manager.save()

答案 1 :(得分:0)

当我于2009年首次开始使用Core Data时,遇到了类似的错误警报问题。我的解决方案过去是,现在仍然是:不要在顶级 main 受管对象上下文中使用Core Data的验证。也就是说,不要实现validateForInsert()。如您所见,即使Core Data确实正确地标记了 true 警报,它也会在保存期间发生,为时已晚,无法对其进行任何智能处理。当用户无法保存其工作时,他们会感到不满意。

您可能希望在 child 受管对象上下文中使用Core Data的验证。在这种情况下,您通常位于视图控制器中,在用户输入验证错误后立即捕获该验证错误,并且您对错误的立即表示对用户来说很有意义。