Swift 2.1 Core Data - 保存具有一对多关系的数据,但如果已经存在则不要添加异构数据

Posted

技术标签:

【中文标题】Swift 2.1 Core Data - 保存具有一对多关系的数据,但如果已经存在则不要添加异构数据【英文标题】:Swift 2.1 Core Data - Save data that has one to many relationship but don't add isome data if already exists 【发布时间】:2016-04-01 01:50:29 【问题描述】:

我有一个创建新配方数据的 ViewController。 要创建新食谱,用户需要填写标题、成分等以及选择其类别。为此,我建立了具有一对多关系的 Category 和 Recipe 实体。

在创建函数中,我需要进行以下搜索以查看类别实体是否已经具有 selectedCategory 的值。

如果 selectedCategory 已经存在于 Category 实体中,我需要找到它的索引并将该类别分配给 Recipe Entity 但我不知道我需要在这里编写什么代码。

for category in categories 
    if category == selectedCategory 

       /* if selectedCategory already exists in Category entity, 
          find its index and assign that category to Recipe entity.*/

     else 
       category.name = selectedCategory
       recipe.category = category
    


context.insertObject(recipe)

do 
    try context.save()
 catch 
    print("Could not save recipe")

【问题讨论】:

如何将类别与 selectedCategory 进行比较,并将 category.name 属性设置为 selectedCategory?类别是什么类型的对象? 你用什么来选择类别? UIPickerView。假设UIPickerView有5个元素(类别),当用户选择甜点== 2(使用委托获取索引)时,插入category.type = @2并插入新食谱recipe.name = "someName",最后将食谱添加到类别[category addRecipe: recipe],然后保存上下文。 我正在使用 tableview 来选择类别。 Category 对象具有 name 属性,默认情况下它将包含 Main、Side、Dessert、Drink 等值。用户可以添加自定义类别名称,但我必须防止插入重复的名称。 您可以使用NSFetchRequest并在其上设置NSPredicate。当用户输入类别名称时,在将值设置为category.name 属性之前,使用谓词将字符串值与保存的Category 实体匹配。执行 fetch 请求时,如果结果计数为 0,则将其保存为新类别,否则将其保存到执行 fetch 时返回的 managedObject 中。 【参考方案1】:

我创建了一个支持 Core Data 的单视图应用程序。

我在数据模型中添加了两个实体:

CategoryEntity 具有属性“名称”。 RecipeEntity 具有属性“title”。

CategoryEntity 与 RecipeEntity 有一个可选的多对一关系,称为“recipes”。它有一个级联删除规则(如果你删除一个类别,所有相关的配方也会被删除)。

RecipeEntity 与 CategoryEntity 具有必需的一对一关系,称为“类别”。

这些关系彼此相反。

以下代码添加了一个配方。它首先获取或创建类别,然后将配方分配给它。

import UIKit
import CoreData

class ViewController: UIViewController 

    @IBOutlet weak var category: UITextField!
    @IBOutlet weak var recipeTitle: UITextField!

    @IBAction func createRecipe(sender: AnyObject) 

        // Apple's out of the box Core Data app exposes a managedObjectContext on the appDelegate, so we'll use it here
        if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate 

            // we have to have a category name ...
            if let categoryName = category.text 

                // ... and a recipe title
                if let recipeTitle = recipeTitle.text 

                    // get the category to associate this recipe with 
                    let categoryEntity = obtainCategoryEntity(categoryName, context: appDelegate.managedObjectContext)

                    // create the recipe entity
                    let recipeEntity = (NSEntityDescription.insertNewObjectForEntityForName("RecipeEntity", inManagedObjectContext: appDelegate.managedObjectContext) as! RecipeEntity)

                    // assign the recipe to the category 
                    //  note that you set up relationships in Core Data by assigning entities, 
                    //  not indexes or id fields
                    recipeEntity.category = categoryEntity

                    // set the recipe's title
                    recipeEntity.title = recipeTitle

                    // save it!
                    do 
                        try appDelegate.managedObjectContext.save()
                        NSLog("saved context")
                     catch let error as NSError 
                        NSLog("failed to save context with error \(error)")
                     catch 
                        fatalError()
                    
                
            
        
    

    func obtainCategoryEntity(name: String, context: NSManagedObjectContext) -> CategoryEntity 

        // this function gets or creates a category entity
        let fetchRequest = NSFetchRequest(entityName: "CategoryEntity")
        fetchRequest.predicate = NSPredicate(format: "name == %@", name)

        //find existing category, if it exists
        if let results = (try? context.executeFetchRequest(fetchRequest)) as? [CategoryEntity] 
            if results.count > 0 
                // we really should only ever have one match, so return it
                return results[0]
            
        

        //category did not exist, so create it
        let categoryEntity = NSEntityDescription.insertNewObjectForEntityForName("CategoryEntity", inManagedObjectContext: context) as! CategoryEntity

        // set the category name
        categoryEntity.name = name

        // return it, but don't save it here - let the save later take care of it
        return categoryEntity
    

【讨论】:

感谢您抽出时间来演示这一点。它工作得很好。现在我知道 NSPredicate 可用于搜索现有记录。

以上是关于Swift 2.1 Core Data - 保存具有一对多关系的数据,但如果已经存在则不要添加异构数据的主要内容,如果未能解决你的问题,请参考以下文章

Core Data 使用 Swift 保存数据

Swift 3 Core Data - 无法保存关系值

如何在 Swift 中的 Core Data 中保存多个项目

Swift 3 Core Data - 如何同步保存上下文?

在 Swift 的 Core Data 中保存自定义类

如何在 Swift 中将字符串数组保存到 Core Data