您如何管理和使用“多对多”核心数据关系?

时间:2011-09-27 16:40:18

标签: iphone objective-c sqlite core-data

我正在创建一个应用并试图使用核心数据,因为它似乎是客观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

有人可以解释你如何在核心数据中做到这一点?

根据核心数据文档,他们说:

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

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

5 个答案:

答案 0 :(得分:53)

彼得:“我有九个老板,鲍勃。” 鲍勃:“再说一次?” 彼得:“ Nine 。”

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

如果使用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];

答案 1 :(得分:4)

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

如果您的问题是“这怎么可能有效”,您可能会发现查看从模型创建的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语法进行简化,但您可以理解。

如果您希望更直接地遍历这种多对多关系作为获取查询的一部分,那么您可以使用谓词做一些事情来获得您想要的内容。有关可以在谓词中添加内容的示例,请参阅Apple's predicate programming guide

答案 2 :(得分:2)

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

@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];

然后您将拥有员工财产中的所有员工:

NSSet *allHisEmployees = manager.employees;

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

我希望它可以解决问题

答案 3 :(得分:1)

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

答案 4 :(得分:0)

你可能会坚持的是如何从抽象数据模型领域转到你在代码中使用的一组对象。如果是这样,请考虑使用mogenerator:

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

这是一个命令行实用程序(不确定这些天XCode集成的工作情况),您将其指向模型,它为您提供了可以使用的数据对象集。除了实体名称之外,还需要为每个实体设置一个对象名称。

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