【问题标题】:How do you manage and use "Many to many" core data relationships?您如何管理和使用“多对多”核心数据关系?
【发布时间】:2011-11-26 05:22:39
【问题描述】:

我正在创建一个应用程序并尝试使用核心数据,因为它似乎是 Objective-C 批准的创建数据存储系统的方式。我的用例涉及“多对多”关系,就像您通常在标准 SQL 系统中看到的那样。我知道目标 C 不是数据库并且工作方式不同。我还在这里查看了文档:

http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW10

还有其他几个地方。然而,我仍然有麻烦。如果您有一个需要使用 SQL 交叉引用表的用例,有人可以向我解释您会怎么做吗?例如:

经理 |员工

经理可能有多个员工,但员工也可能有多个经理。在 SQL 中,我会创建一个交叉引用表,然后使用它。

示例:http://www.tomjewett.com/dbdesign/dbdesign.php?page=manymany.php

有人能解释一下如何在 Core data 中做到这一点吗?

根据核心数据文档,他们是这样说的:

“您使用双对多关系定义多对多关系。第一个对多关系从第一个实体到第二个实体。第二个对多关系从第二个实体到第一个实体实体。然后您将每个设置为另一个的倒数。(如果您有数据库管理背景并且这引起您的担忧,请不要担心:如果您使用 SQLite 存储,Core Data 会自动创建中间连接表你。)”

但是,除了“不担心”之外,我不知道这怎么可能?

【问题讨论】:

  • 不,因为那个人引用了一个连接表。根据我在文档中阅读的内容,您不需要创建连接表吗?此外,我认为他在询问有关获取数据的问题。

标签: iphone objective-c sqlite core-data


【解决方案1】:

简单的答案是在xCode中设置核心数据时,从两端将关系标记为一对多。这实质上创造了多对多。它在某处的苹果文档中,但我找不到 URL。

【讨论】:

  • 但是,呃 - 我如何查看哪些员工有经理,哪些经理有员工?我的意思是,否则它们只会是一个很大的列表?
  • 您会说employee.managers 来为员工获取一组经理。对于经理,您只需说 manager.employees 并获取该经理的所有员工实体的集合。 (“员工”和“经理”都是指一个人的实体的具体实例)。
【解决方案2】:

如果您的问题是“如何在核心数据中做到这一点”,那么答案与您描述的完全一样。在每个实体中创建一对多关系,并将每个实体定义为另一个实体的逆。

如果您的问题是“这怎么可能工作”,您可能会发现查看从您的模型创建的 sqlite 数据库以了解它是如何设置的很有用。 CoreData 非常擅长制作它,因此您不必关心细节,但如果您坚持了解细节,则没有什么能阻止您查看数据以了解它在做什么。

一旦你有了这个,你会根据需要遍历关系来获得你想要的属性。您可以使用 NSManagedObject 实例在代码中执行此操作。例如:

NSManagedObject *manager = // get a reference to a manager here
NSSet *employees = [manager valueForKey:@"employees"];
for (NSManagedObject *employee in employees) {
    NSString *employeeName = [employee valueForKey:@"name"];
    // Do whatever else you want here
}

也可以使用直接属性访问而不是 KVO 语法来简化此示例,但您明白了。

如果您希望在 fetch 查询中更直接地遍历这种多对多关系,那么您可以使用谓词做一些事情来获得您想要的东西。请参阅 Apple's predicate programming guide 了解可以在谓词中放入什么的示例

【讨论】:

  • 嗯,知道它是如何工作的很好,但我真正想知道的是如何访问交叉引用表?我的意思是,您还应该如何将这两个实体实际映射到彼此?一个实体的属性并不具有另一个实体的所有属性。
  • 我稍微更新了响应以包含使用代码访问交叉引用数据的示例。如果您正在寻找特定类型查询的示例,请说明您在寻找什么,我们可能会提供一个谓词,您可以使用它来实现您想要的。
【解决方案3】:

您可能遇到的问题是如何从抽象数据模型领域获得您在代码中使用的一组对象。如果是这样,请考虑使用 mogenerator:

http://rentzsch.github.com/mogenerator/

这是一个命令行实用程序(不确定现在 XCode 集成的效果如何),您可以将它指向一个模型,它会为您提供可以使用的数据对象集。除了实体名称之外,您还需要为每个实体设置一个对象名称。

生成的数据对象具有诸如employee.managers 之类的调用,这将为您提供一组员工的经理实体,反之亦然。

【讨论】:

  • @MohsinKhubaibAhmed - 是的,Mogenerator 仍然有效,我最近一直在从事将其用于核心数据对象生成的项目。
  • 很好,我会详细检查一下.. 你能推荐任何资源来让我继续这样做吗?如在风景如画的演示或其他东西中
  • 没关系,我找到了:medium.com/@yzhong.cs/…
【解决方案4】:

假设您的数据库中有两个实体,员工和经理。它们在代码中看起来像这样:

@interface Employee :  NSManagedObject  
{

}

@property (nonatomic, retain) NSNumber * id;
@property (nonatomic, retain) NSSet* managers;

@interface Manager :  NSManagedObject  
{

}

@property (nonatomic, retain) NSNumber * id;
@property (nonatomic, retain) NSSet* employees;

假设您想检索经理编号为 1 的所有员工,您只需从数据库中获取经理对象:

NSNumber *managerID = [NSNumber numberWithInt:1];
NSEntityDescription * entityDescription = [NSEntityDescription entityForName:@"Manager"                                                       inManagedObjectContext:managedObjectContext]; 
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];  
[request setEntity:entityDescription];  
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %d", @"id", managerID];   
[request setPredicate:predicate];
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
Manager *manager = [array objectAtIndex:0];

然后您会将其所有员工都放在 employees 属性中:

NSSet *allHisEmployees = manager.employees;

检索给定员工的经理是完全相同的。

希望能解决问题

【讨论】:

    【解决方案5】:

    Peter:“我有 9 个 老板,Bob。” 鲍勃:“再说一遍?” 彼得:“九个。”

    把你的大脑从数据库中拿出来。不要问如何访问交叉引用表。询问如何为经理查找员工或为员工查找经理。

    如果您使用 NSManagedObject 的自定义子类,则可以将属性声明为记录的。那么你可以简单地说:

    NSSet *mgrsEmployees = mgr.employees;
    NSSet *employeesMgrs = employee.managers;
    

    这不会为您提供所有员工和所有经理,只会为您提供该经理的所有员工和该员工的所有经理。改变关系:

    [mgr addEmployeesObject:newEmployee];
    [newEmployee addManagersObject:mgr]; // not necessary, automatic if you define inverse
    
    [mgr removeEmployeesObject:transferredEmployee];
    [transferredEmployee removeManagersObject:mgr]; // not necessary
    [newMgr addEmployeesObject:transferredEmployee];
    [transferredEmployee addManagersObject:newMgr]; // not necessary
    

    您只需要执行每对语句中的一个,它会隐含地执行另一个,前提是您已将经理和员工定义为彼此的倒数。

    如果不使用自定义子类,访问会比较冗长

    NSSet *mgrsEmployees = [mgr valueForKey:@"employees"];
    NSSet *employeesMgrs = [employee valueForKey:@"managers"];
    
    NSMutableSet *changeMgrsEmployees = [mgr mutableSetValueForKey:@"employees"];
    [changeMgrsEmployees addObject:newEmployee];
    // not necessary
    NSMutableSet *changeEmployeesMgrs = [employee mutableSetValueForKey:@"managers"];
    [changeEmployeesMgrs addObject:mgr];
    

    等等

    【讨论】:

    • 这是我见过的关于堆栈溢出的最佳答案之一。太感谢了!我的眼里几乎含着泪水,我对此感到非常困惑。
    • 如何在保存上下文之前获取上下文中的所有员工?
    • 是否保存上下文无关紧要。无论上下文是否保存,在代码中访问员工的结果都是相同的。是否保存仅影响您停止和启动程序或丢弃上下文等时发生的情况。
    • 我想显示一个实体的 4 列 另一个实体的 2 列,我该怎么做呢?
    • 假设有 2 个实体具有多对多关系(A 和 B)。假设我为 A1 记录添加 B1 和 B2,为 A2 记录添加 B1 和 B3。对于 B1,我会自动得到(A1 和 A2)吗?
    猜你喜欢
    • 1970-01-01
    • 2012-03-08
    • 2016-06-30
    • 1970-01-01
    • 2013-10-27
    • 2011-02-18
    • 2016-09-08
    • 1970-01-01
    相关资源
    最近更新 更多