如何基于另一个实体的一对多关系访问 CoreData 实体?

Posted

技术标签:

【中文标题】如何基于另一个实体的一对多关系访问 CoreData 实体?【英文标题】:How to access CoreData entities based on a to-many relationship of another entity? 【发布时间】:2012-04-11 16:16:09 【问题描述】:

我正在使用示例库存应用程序学习 CoreData。我的数据模型有 2 个实体,“拥有”和“资产类型”。财产与名为“assetType”的资产类型具有一对一的关系,而资产类型与名为“财产”的财产具有一对多的关系。每个 Possession 只有一个 Asset Type,但 Asset Types 有很多 Possession。

我想根据资产类型将表格视图分类为多个部分。不过,我需要一些帮助来填充我的数据结构。

这是我将如何为我的表格视图控制器建模

表部分的 NSArray 数组中的每个部分对象都是一个 NSDictionary,有 2 个键,@"Header" - 将是资产类型,@"Possessions" 是该资产类型的财产数组。

我可以处理从这个结构构建我的表格视图没有问题。我还可以处理从 CoreData 获取资产类型到我的字典的标题键中。我被难住的地方是如何利用资产类型与财产的多对多关系,以便我可以将财产放入字典的数组中。

如何将每个资产类型的财产放入一个数组中?

我是否需要使用谓词发出获取请求以获取具有匹配资产类型的财产,还是有更简单的方法? - 似乎效率低下,因为它必须检查所有财产以进行比赛!?!?!?!?

AssetType 实体的一对多关系“拥有”是 AssetType 实体的可访问属性吗?如果是这样,我该如何访问它?它返回什么?

我不是在寻找免费代码,但如果需要,我愿意发布我的代码。我真正想要的是知道解决这个问题的最佳方法,并可能指出在线有用的信息来完成这个。我不是一个完整的新手,但我仍然无法理解 CoreData,到目前为止,Apple 文档在这个主题上仍然让我很困惑。感谢您提供的任何帮助。

【问题讨论】:

【参考方案1】:

如果你使用 Xcode 默认的 NSManagedObject 模板创建了 AssetType 类(见图)

您的 AssetType.h 中应该有类似的内容:

@interface AssetType : NSManagedObject

@property (nonatomic, retain) NSSet *possessions;

@end

@interface AssetType (CoreDataGeneratedAccessors)

- (void) addPossessionsObject:    (Possession *) value;
- (void) removePossessionsObject: (Possession *) value;
- (void) addPossessions:          (NSSet *) value;
- (void) removePossessions:       (NSSet *) value

@end

因此,如果您有一个 AssetType 对象,您可以通过possessions 属性访问与其相关的所有 Possession 对象。虽然默认情况下它没有排序,因此要将这些对象作为数组访问,您需要调用集合的 -allObjects 方法,该方法将集合中的对象作为数组返回,然后可能以某种方式对这些对象进行排序。

编辑:

此外,即使您没有以这种方式创建 NSManagedObject 子类并且它还没有实现 possessions 属性,您也可以按照与上面示例中所述相同的方式将此属性添加到类中并实现它在 AssetType.m 中为 @dynamic possessions

【讨论】:

感谢您的回答。到目前为止,我将 Possession 作为 NSManaged Object 的子类,但只是直接从对象上下文中获取资产类型,到目前为止,它仅用于 PossessionDetailViewController 中的标签。让我确保我对您的理解正确。为 AssetType 创建一个子类,将 AssetType 对象获取到一个数组中,以用于制作我的字典。循环遍历该数组 [..将标签添加到我的标题键 [assetTypevar label]...] 然后我的财产数组 pArray = [assetTypevar 财产] allObjects] 是的,pArray = [[assetTypevar possessions] allObjects] 应该可以工作。对多关系通常由 NSSet 对象表示(除了在 ios 5 中,Apple 引入了直接表示为 NSArrays 的有序对多关系,但在之前的 iOS 版本中不支持这些关系) 谢谢!最后一个问题。在我创建 AssetType 子类之后,我是否还需要重新生成我的财产类,或者它们会好起来吗? Possession 类应该没问题,因为 AssetType 类的生成只创建 AssetType.h 和 AssetType.m 文件,不会触及其他任何东西。【参考方案2】:

根据我正在阅读的内容,我怀疑这比您想象的要容易得多。

在我看来,您已经设想在您的 UITableController 的 tableView:cellForRowAtIndexPath: 方法中使用字典数据结构,而您可能根本不需要使用它。

当您实例化 Table 视图控制器时,(viewDidLoad: 可能是最合适的地方)只需使用如下代码检索您的资产:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Asset" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) 
    // handle errors here


[fetchRequest release];

如有必要,将 fetchedObjects 数组分配给 NSArray 类型的实例变量,以便您可以在管理表的 UITableViewController 类中的多个位置引用它。然后在上面的代码之后你可以做这样的事情:

self.assets = fetchedObjects;

如果您尚未为资产 NSManagedObject 创建自定义子类,则数组中的每个对象都将是 NSManagedObject 类型,您需要将其读入该类型的变量中。

当您需要与资产相关的所有物列表时,它已经存在于数组中的每个资产对象中(这就是 CoreData 的美妙之处,如果它实际上没有在内存中实例化,那么当您尝试访问该属性时, CoreData 会自动为你实例化它)。

假设您没有为您的 NSManagedObject 定义自定义类,那么您的数组对象将属于该类型。将数组中的一个资产对象分配给一个名为(适当地)资产的局部变量,

例如,这会将索引 0 处的对象分配给局部变量。

NSManagedObject *asset = [self.assets objectAtIndex:0];

您可以使用代码获得您的财产:

NSSet *assetPossessions = [asset valueForKey:"@possessions"];

(假设在 xCode 的模型编辑器中定义的关系已被命名为“possessions”)

或者,如果您为 Asset NSManagedObject 生成了自己的自定义子类,那么这可能是一个更好的示例:

MyManagedAssetObject *asset = [self.assets objectAtIndex:0];
NSSet *assetPossessions = asset.possessions;

注意在这个例子中,我假设你没有使用 NSFetchedResultsController。实际上,使用一个表来管理一个表甚至更容易,但是就像编程的情况一样,只有当你知道“只有一件事”时才会更容易,因此(自相矛盾地)使答案复杂化。既然你没有提到它,我就假设你没有使用它。

希望这会有所帮助。保罗

【讨论】:

哦,我应该提到您可能想要订购 fetch 请求 - 请查看 Xcode 代码模板以执行此操作(在代码 sn-p 库中)。此外,如果使用 iOS 5.0,您可能希望选择将资产作为 NSOrderedSet 存储 - 因此订单存储在 CoreData 对象中。如果您在排序方面需要更大的灵活性,请通过首先将 NSSet(本质上是无序的)转换为 NSArray 来重新排序 NSSet assetPossessions: NSArray *possessionSetAsArray = [assetPossessions allObjects]; 感谢您的反馈。我没有使用 NSFetchedResultsController。我一直在使用之前写的一本书,我相信它是 iOS5 的新书。我选择了字典结构数组,因为它允许我在我的表格视图中拥有更简单的代码,其中我的数据模型已经分组到标题下的部分中。我只是在应用程序启动时加载 section 数组,并在运行时根据需要刷新以进行编辑、删除、删除或编辑 Possessions 和 Assets。我只是使用我的索引路径部分来获取正确的字典和行以从它的数组中获取我需要的内容。

以上是关于如何基于另一个实体的一对多关系访问 CoreData 实体?的主要内容,如果未能解决你的问题,请参考以下文章

IOS:通过一对多关系获取核心数据

NSArrayController 如何对一对多关系进行排序?

如何获取所有对象A的一对多关系B的所有属性的NSSet

快速获取具有一对多关系的核心数据

GAE ndb 存储大型一对多关系的最佳实践

iPhone Core Data - 访问具有多种关系的深层属性