Swift3 - 在核心数据中插入关系

Posted

技术标签:

【中文标题】Swift3 - 在核心数据中插入关系【英文标题】:Swift3 - Insert Relation In Core Data 【发布时间】:2017-06-03 17:55:00 【问题描述】:

我有两个实体,即

    诊所 部门

它们之间的关系是多对多的。即一个诊所有很多科室,一个科室有很多相关联的诊所。

我已经在coredata.xcdatamodeld 中设置了实体并生成了NSManagedObject 类。 PFA 图

我有以下代码负责插入部门和诊所

import Foundation
import CoreData
import SwiftyJSON
import Kingfisher

class InstallManager 

    let moc = NetworkManager.managedObjectContext
    let data: JSON!

    init(withData data: JSON) 
        self.data = data
    

    // Install Department
    private func installDepartment() 
        for(_,jsonData):(String, JSON) in self.data["deparment"]["list"] 
            let department = NSEntityDescription.insertNewObject(forEntityName: "Department", into: moc)
            department.setValue(jsonData["id"].int32, forKey: "id")
            department.setValue(jsonData["name"].string, forKey: "name")
            department.setValue(jsonData["icon"].string, forKey: "icon")
            department.setValue(jsonData["slug"].string, forKey: "slug")
            department.setValue(jsonData["revision"].int32, forKey: "revision")
            do 
                try moc.save()
             catch 
                fatalError("\(error)")
            
        
    

    // Install Clinic
    private func installClinic() 
        let departmentList = fetchDepartmentList()
        for (_,jsonData):(String, JSON) in self.data["clinic"]["list"] 
            let coverPictureAbsolute = "\(jsonData["cover_picture"].string!)"
            let coverPictureRelative = (coverPictureAbsolute as NSString).lastPathComponent
            let clinic = NSEntityDescription.insertNewObject(forEntityName: "Clinic", into: moc)
            clinic.setValue(jsonData["id"].int32, forKey: "id")
            clinic.setValue(jsonData["name"].string, forKey: "name")
            clinic.setValue(jsonData["slogan"].string, forKey: "slogan")
            clinic.setValue(jsonData["profile"].string, forKey: "profile")
            clinic.setValue(jsonData["address"].string, forKey: "address")
            clinic.setValue(jsonData["telephone"].string, forKey: "telephone")
            clinic.setValue(jsonData["email"].string, forKey: "email")
            clinic.setValue(jsonData["website"].string, forKey: "website")
            clinic.setValue(coverPictureRelative, forKey: "cover_picture")
            clinic.setValue(jsonData["latitude"].string, forKey: "latitude")
            clinic.setValue(jsonData["longitude"].string, forKey: "longitude")
            clinic.setValue(jsonData["slug"].string, forKey: "slug")
            clinic.setValue(jsonData["revision"].int32, forKey: "revision")

            let clinicEntity = clinic.value(forKeyPath: "departments") as! Clinic
            for department in departmentList 
                clinicEntity.addToDepartments(department)
                print(department.name!)
            

            do 
                try moc.save()
             catch 
                fatalError("\(error)")
            
        
    

    private func fetchDepartmentList() -> [Department] 
        var departmentList:[Department]!
        let request: NSFetchRequest<Department> = Department.fetchRequest()
        do 
            departmentList = try moc.fetch(request)
         catch 
            fatalError("Cannot fetch clinics list \(error)")
        
        return departmentList
    

    public func install() 
        self.installDepartment()
        self.installClinic()
    

我的问题是在插入诊所和部门之间的关系时,我有想要设置与诊所关系的部门 ID 列表。如您在上面的代码中看到的,我尝试了以下代码

let departmentList = fetchDepartmentList()
let clinicEntity = clinic.value(forKeyPath: "departments") as! Clinic
for department in departmentList 
    clinicEntity.addToDepartments(department)
    print(department.name!)

但是 ClinicEntity 行向我抛出以下错误

Could not cast value of type '_NSFaultingMutableSet' to 'APP.Clinic'

这里有什么问题?如何设置关系?

更新:

这是从核心数据(NSManagedObject 子类)自动生成的类

// filename: Clinic.swift
import Foundation
import CoreData

@objc(Clinic)
public class Clinic: NSManagedObject 



// filename: Clinic+CoreDataProperties
import Foundation
import CoreData

extension Clinic 

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Clinic> 
        return NSFetchRequest<Clinic>(entityName: "Clinic");
    

    @NSManaged public var address: String?
    @NSManaged public var cover_picture: String?
    @NSManaged public var email: String?
    @NSManaged public var id: Int32
    @NSManaged public var latitude: NSDecimalNumber?
    @NSManaged public var longitude: NSDecimalNumber?
    @NSManaged public var name: String?
    @NSManaged public var profile: String?
    @NSManaged public var revision: Int32
    @NSManaged public var slogan: String?
    @NSManaged public var slug: String?
    @NSManaged public var telephone: String?
    @NSManaged public var website: String?
    @NSManaged public var departments: NSSet?



// MARK: Generated accessors for departments
extension Clinic 

    @objc(addDepartmentsObject:)
    @NSManaged public func addToDepartments(_ value: Department)

    @objc(removeDepartmentsObject:)
    @NSManaged public func removeFromDepartments(_ value: Department)

    @objc(addDepartments:)
    @NSManaged public func addToDepartments(_ values: NSSet)

    @objc(removeDepartments:)
    @NSManaged public func removeFromDepartments(_ values: NSSet)


【问题讨论】:

【参考方案1】:

对于to-many 关系,您需要获取mutableSetValueForKey,因为类型是NSSet 而不是Clinic

let clinicEntity = clinic.mutableSetValue(forKey: "departments")
for department in departmentList 
    clinicEntity.add(department)
    print(department.name!)

或更简单

let clinicEntity = clinic.mutableSetValue(forKey: "departments")
clinicEntity.addObjects(from: departmentList)

要使用自动生成的方法,您可以替换

let clinicEntity = clinic.value(forKeyPath: "departments") as! Clinic
   for department in departmentList 
   clinicEntity.addToDepartments(department)
      print(department.name!)
   

clinic.addToDepartments(NSSet(array: departmentList))

PS:我建议使用更方便的点符号,例如

department.id = jsonData["id"].int32
department.name = jsonData["name"].string
department.icon = jsonData["icon"].string
department.slug = jsonData["slug"].string
department.revision = jsonData["revision"].int32

【讨论】:

这行得通,谢谢。我想知道核心数据(NSManagedObject)生成的类中可用的方法@NSManaged public func addToDepartments(_ value: Department)有什么用处 我没有注意到这些方法是自动生成的。完美,用它们代替mutableSetValueForKey 就是这样,我不能。它抛出了错误,我已经用它自动生成的两个类更新了我的问题。 PS:既然你使用NSManagedObject子类,为什么不写clinic.name = jsonData["name"].string而不是clinic.setValue(jsonData["name"].string, forKey: "name") 如果我能做到,那就太棒了,但是因为诊所是 NSEntityDescription 的一个实例,我该如何让它工作?你能帮我举个例子吗?

以上是关于Swift3 - 在核心数据中插入关系的主要内容,如果未能解决你的问题,请参考以下文章

核心数据关系,如何从关系中插入和检索数据

一对多关系核心数据获取数据

在核心数据中插入新的关系数据

一对多关系核心数据获取数据

将一个对象插入多个关系 - IOS核心数据

核心数据需要时间来插入具有获取实体的记录并设置为关系