如何将目标NSManagedObject添加到具有反向多对多核心数据关系的另一个NSManagedObject而不复制目标NSManagedObject?

时间:2016-08-18 11:17:09

标签: core-data nsfetchedresultscontroller nsmanagedobject nsmanagedobjectcontext nsset

我遇到了一个问题,我花了十几个小时来找到解决方案,我已经取得了一些进展,但仍然没有得到我想要达到的理想状态。我现在仍然在寻找解决方案,而我真的很感激任何人都可以分享建设性解决方案的任何见解。

问题:

  • 如何将主列表中的目标NSManagedObject作为一个对象添加 另一个NSManagedObject中的引用与反转 没有的每个NSManagedObject之间的多对多关系 在主列表中创建重复的目标NSManagedObject。

注意:

  • 以下示例使用了完整数据模型图的类比 到我的真实项目。这个比喻是我能够最好地描述这个问题的 我有,虽然类比中的对象不完全相同 实际项目中对象的名称。

我现在拥有的内容:

  • 成分对象的主列表,在每个成分对象中是唯一的 其他

  • 食谱对象列表,每个对象都希望有不同的对象 成分对象来定义配方对象。

我想达到什么目标:

  • 成分对象可以多次插入到单个配方对象中,每个插入作为唯一计数,而不是将相同的成分视为一个单一计数。

  • 我不想复制里面的每个成分对象 主列表能够为每个添加多个成分对象 配方对象或交叉多个配方对象。

我尝试了什么:

  • 使用核心数据管理配料和配方为2 NSManagedObjects。

  • 在成分管理对象上创建了一个名为“allHostRecipes”的关系属性,并将其设置为与配方管理对象的“to-Many”关系

  • 在配方管理对象上创建了一个名为“allUsedIngredients”的关系属性,并将其设置为与成分管理对象的“to-Many”关系。

  • 这两个关系设置为“反向”。
  • 我有一个带有表格视图的配方描述视图,其中列出了配方中包含的所有成分。
  • 我创建了另一个成分选择表视图,可以在配方描述视图中触发,以选择每种成分,这些成分将添加到配方中。
  • 每次在“成分选择表视图”中选择一种成分时,我会在NSFetchedResultsController上调用objectAtIndexPath(_ :),该成分用于成分的主要列表中的成分表视图,以在其ManagedObjectContext中查找所选的成分对象。
  • 然后我将选定的成分管理对象(SelectedIngredientManagedObject)传递回配方描述视图,并在NSFetchedResultsController上调用mutableSetValueForKey(" allUsedIngredients")。addObject(SelectedIngredientManagedObject),用于获取成分包含在配方对象内部。

  • “NSFetchedResultsController用于成分表视图从成分'主列表”和“NSFetchedResultsController用于获取包含在配方对象内的成分”是“表视图配方描述”中的单独实例变量查看“和”成分选择表视图“。但是他们引用了相同的ManagedObjectContext。

我现在得到了什么:

  • 可以将选定的成分管理对象添加到配方中。
  • 但是,如果我多次选择相同的成分,它只会在配方描述视图的表视图中计数一次,而不是每次插入显示多个计数,这不是我想要实现的如上所述。

我的问题:

  • 我应该做些什么或进行调整以实现我的功能 如上所述?

我认为解决问题的方向是:

  • 在定义“多对多”时,我还应该做些什么? 核心数据模型中的关系?
  • “to-Many”引用使用NSSet的事实是否导致计数问题?
  • 是否有必要创建多个ManagedObjectContext以实现所需的功能?
  • 我应该将选定的成分管理对象克隆为新的成分管理对象吗?我曾经尝试过,它会在配料主列表中添加重复的成分。这也不是我想要的。如果我需要克隆它,我该怎么做呢?

我非常感谢您有时间查看它,我期待着您的见解。非常感谢你。

此致

奈特

1 个答案:

答案 0 :(得分:2)

您需要稍微重新构建数据:删除从RecipeIngredient的多对多关系,并将其替换为中间实体(找到一个好名字很难,让我们这样做说RecipeIngredientDetails)。

创建一个从RecipeRecipeIngredientDetails的一对多关系,比如说allUsedIngredientDetails,用反向(转换为一个)recipe

同样创建一个从IngredientRecipeIngredientDetails的一对多关系,比如allHostRecipeDetails,用反向(to-one)ingredient

这解决了直接多对多关系的问题,其中每个Recipe只能与每个Ingredient相关一次。 (你是对的,这部分是由于关系被建模为集合的结果,它不能有重复的成员)。您有两种选择:您可以添加多个RecipeIngredientDetails个对象,每个对象与同一个RecipeIngredient对相关。每个这样的对象可能代表成分的标准基础量。请注意,每个Recipe / Ingredient对不能只有一个对象,并尝试将该对象多次添加到同一Recipe:给定的Recipe和给定的RecipeIngredientDetails对象最多只能相关一次。

但是向RecipeIngredientDetails添加属性可能会更好,比如说quantity。然后,每个Recipe / Ingredient对只需要一个这样的对象,并且可以更新quantity属性以反映适合该配方的成分量。

这是Modeling a Relationship Based on Its Semantics上的CoreData编程指南部分中提到的方法:

  

对于这种关系,请使用中间(联接)实体。中间实体的一个优点是您还可以使用它来为关系添加更多信息。

它相当于将带有外键和其他列的连接表添加到SQL数据库。我不知道在CoreData中实现目标的任何更简单的方法 - 没有办法直接向关系添加属性。

关于您在评论中提到的订购问题,您已在实体中添加了" Double类型属性以跟踪订单"。如果您只有两个实体和多个关系,那么您将订单属性添加到Ingredient然后(例如)如果"面粉"是" Bread"的第一个成分,它必须是其使用的每个其他食谱的第一个项目。在我描述的方法中,您将属性添加到中间实体{{1索引(就数量而言)取决于两者配方和成分。

但是,对于索引,我应该提到另一个选项:您可以(在数据模型编辑器中)将配方与RecipeIngredientDetails之间的关系定义为 ordered 。结果属性将是一个有序集(因此您可以插入,移除或移动项目以实现正确的顺序)。