【问题标题】:How to set an entities attribute via relationship?如何通过关系设置实体属性?
【发布时间】:2016-11-30 15:18:24
【问题描述】:

我有以下实体和关系

我希望能够设置一个练习,使其例行名称关系的结果为零,如果这有意义吗?以便以后在形成例程实体时将其设置为例程名称。

我的问题是,你如何设置这种属性?我正在尝试以下代码,但它会导致致命的崩溃:

userExercise.usersroutine?.name = nil

我的逻辑是我进行练习并遵循与 name 属性的关系并将其设置为 nil?

感谢您对我的逻辑的任何更正和澄清

编辑:添加了我现有的锻炼和日常保存功能

    func createExercise() {
    guard let managedObjectContext = managedObjectContext else { return }
   if let userExercise = userExercise {
        userExercise.name = userExerciseName.text
        userExercise.sets = Int64(userSetsCount)
        userExercise.reps = Int64(userRepsCount)
        userExercise.weight = Double(self.userExerciseWeight.text!)!
        userExercise.id = UUID().uuidString
        userExercise.routine = nil
    }
    do {
        try managedObjectContext.save()
    } catch {
        fatalError("Failure to save context: \(error)")
    }
}

例程创建:

    func createRoutine() {

    guard let managedObjectContext = managedObjectContext else { return }
    let userRoutine = UserRoutine(context: managedObjectContext)
    userRoutine.name = workoutNameTextfield.text

    do {
        try managedObjectContext.save()
    } catch {
        fatalError("Failure to save context: \(error)")
    }
}

当前获取请求:

    fileprivate lazy var fetchedResultsController: NSFetchedResultsController<UserExercise> = {

    let fetchRequest: NSFetchRequest<UserExercise> = UserExercise.fetchRequest()
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
    fetchedResultsController.delegate = self
    return fetchedResultsController

【问题讨论】:

  • 这是因为你的 usersroutine 值本身是 nil 并且你试图在它上面设置 name。说得通?首先尝试为例程分配一个值,然后根据需要将 name 设置为 nil。
  • 我明白了,那么正确的方法是什么?简单地使用 userExercise.usersroutine = nil 直到我有要设置的名称?
  • 你能解释一下你想在日常和锻炼之间建立什么样的关系,以便我更好地理解你的问题并给出一个可行的解决方案。
  • 1 个例程将包含许多练习,但一个练习只属于一个例程,我希望例程构建器查看练习并将所有具有 nil 关系的练习导入其中,因为它们还没有分配给其他例程,然后我可以保存例程,将其名称应用于那些替换 nil 的练习,创建一个带有属性练习的例程。套路在创建练习时不存在,它是在之后创建并设置它的名称

标签: swift core-data entity relationship


【解决方案1】:

请检查下面的实现我已经创建了一些练习和例程。还要阅读代码中的 cmets,这将帮助您弄清楚如何去做。

添加新练习的功能

func createExercise(weight: Int16, respetitions: Int16, name: String, routine: Routine?)->Exercise? {
    let context = getMainContext()
    let exercise = NSEntityDescription.insertNewObject(forEntityName: "Exercise", into: context) as! Exercise
    exercise.setValue(weight, forKey: "weight")
    exercise.setValue(name, forKey: "name")
    exercise.setValue(respetitions, forKey: "rep")

    do {
        try context.save()
        return exercise
    }
    catch
    {
        fatalError("unable to Ssavve")
    }
}

添加新程序的功能

func createRoutine(name: String, exercises:[Exercise]) {
    let context = getMainContext()
    let routine = NSEntityDescription.insertNewObject(forEntityName: "Routine", into: context) as! Routine
    routine.name = name

    //Iterate over Exercise objects & check if routine is nil. 
   //Here if routine is not nil it menas your exercise is already assigned to a routine. 
   //If routine is nil assign routine.addToRelationship(<#T##value: Exercise##Exercise#>) and Also assign routine to the execise.

     do {
            try context.save()
        }
        catch
        {
            fatalError("unable to Ssavve")
        }

}

获取主 NSManagedObjectContext 的函数,我们可以在其上执行核心数据操作

func getMainContext() -> NSManagedObjectContext {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    return appDelegate.persistentContainer.viewContext
}

下面,我先做几个与套路无关的练习

"习题创建时该套路不存在,后创建并设置名称"

然后通过一些练习来创建例程 (You can refer to other answer on how to fetch exercises with routine as nil values)

func initializer() {
        //I'm adding exercises first without routines
        let ex1 = self.createExercise(weight: 10, respetitions: 4, name: "Exercise1", routine: nil)
        let ex2 = self.createExercise(weight: 5, respetitions: 10, name: "Exercise2", routine: nil)
        let ex3 = self.createExercise(weight: 20, respetitions: 2, name: "Exercise3", routine: nil)
        let ex4 = self.createExercise(weight: 5, respetitions: 10, name: "Exercise2", routine: nil)

        self.createRoutine(name: "Routine 1", exercises: [ex1!, ex2!]) //You can pass all the exercises or use fetch request to query exercises with routine as nil
        self.createRoutine(name: "Routine 2", exercises: [ex3!, ex4!])

        self.createRoutine(name: "Routine 3", exercises: [ex1!, ex2!]) //This routine shall not be adding any execises as they are already added to othe routines
    }

更新创建例程函数以查询用户例程为nil的UserExercise的结果

func createRoutine() {

    guard let managedObjectContext = managedObjectContext else { return }
    let userRoutine = UserRoutine(context: managedObjectContext)
    userRoutine.name = workoutNameTextfield.text

//Getting nil value User Exercises        
    let request: NSFetchRequest<UserExercise> = UserExercise.fetchRequest()
                request.predicate = NSPredicate(format: "usersroutine == nil")
                do {
                    let appDelegate = UIApplication.shared.delegate as! AppDelegate
                    let context = appDelegate.persistentContainer.viewContext
                    let queryResults = try context.fetch(request)

                    //I like to check the size of the returned results!
                    print ("num of results = \(queryResults.count)")

                    //You need to convert to NSManagedObject to use 'for' loops
                    for exercise in queryResults as [NSManagedObject] {
                        //get the Key Value pairs (although there may be a better way to do that...
                        print("Exercise NAME: \(exercise.value(forKey: "name"))")
                    }
                } catch {
                    print("Error with request: \(error)")
                }


        do {
            try managedObjectContext.save()
        } catch {
            fatalError("Failure to save context: \(error)")
        }
    }

【讨论】:

  • 我和你在一起,直到迭代练习以添加它们/将它们的 nil 例程更改为我保存的例程,我无法弄清楚如何实现该部分,我使用 NSFetchedResultsControllerDelegate 我假设使用查询 nil 练习是正确的方法,但不知道该怎么做。核心数据实体中还需要什么类型的属性来存储练习数组?
  • getUnmappedExercise 在我的 VC 中也导致了很多错误,因为它现在是一个函数,而不是 OP 中的代码,难道不能简单地编辑该代码来执行任务吗?
  • 我添加了该功能,以便您仅了解实现部分。查看编辑,我已删除 func,尝试使用此代码并告诉我您是否看到任何结果(打印语句)。
  • 我收到错误无法将类型 '() -> ()' 的值转换为指定类型 'NSFetchedResultsController',我保留了文件私有惰性 var fetchedResultsController: NSFetchedResultsController = { from我之前的代码作为 VC 需要它作为参考,这是原因吗?
  • 我在 Xcode 8.0 上没有看到任何编译时问题,我检查了。
【解决方案2】:

您似乎根本不需要使用name 属性。该属性应该用于存储UserRoutine 的实际名称,而不是任何基于关系的。

Core Data 中实体之间的关系不依赖于实体的特定属性,而是实体之间的关系。

“我希望例程构建器查看练习并将关系中具有 nil 的所有练习导入其中”

所以...

创建一个获取请求以获取UserExercise 中没有相关UserRoutine 的所有实体(即userroutine 为零)。

let orphanedExerciseFetchRequest = NSFetchRequest(entityName: "UserExercises")
orphanedExerciseFetchRequest.predicate = NSPredicate(format: "userroutine == nil)

执行此获取请求以获取 UserExercises 数组(没有相关例程)

let orphanedExercises = managedObjectContext.executeFetchRequest(orphanedExerciseFetchRequest())

“使用归因练习创建例程”

将获取的UserExercise 实体的属性userRoutine 设置为您的例程(并且不要忘记将更改保存在您的托管对象上下文中)。

myRoutine.userexercises = orphanedExercises

稍后,如果您想针对特定例程进行练习:

let fetchRequest = NSFetchRequest(entityName: "UserExercises")
fetchRequest.predicate = NSPredicate(format: "userroutine == %@", someUserRoutine)

【讨论】:

  • 注意:不是用 Xcode 编写的,所以可能有一些拼写错误等,但希望这能帮助你朝着正确的方向前进。
  • 谢谢,我已经用我当前的 fetch 请求更新了我的 OP,可以修改它以合并此代码还是需要单独的方法?
  • 尝试了以下但我得到了致命的错误? fileprivate 惰性 var fetchedResultsController: NSFetchedResultsController = { let orphanedExerciseFetchRequest: NSFetchRequest = UserExercise.fetchRequest() orphanedExerciseFetchRequest.predicate = NSPredicate(format: "userroutine == nil") let fetchedResultsController = NSFetchedResultsController(fetchRequest: orphanedExerciseFetchRequest, managedObjectContext: self.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil) fetchedResultsController.delegate = self return fetchedResultsController}()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多