Re: Core Data Many2Many Relationships
Re: Core Data Many2Many Relationships
- Subject: Re: Core Data Many2Many Relationships
- From: mmalcolm crawford <email@hidden>
- Date: Thu, 4 Aug 2005 19:13:00 -0700
On Aug 4, 2005, at 3:06 PM, Chris Blunt wrote:
Thanks for the advice so far. Although I can see what I need to do
(subclass the nsmanagedobject class and implement the addExraObject
code...), I can't figure out how to work it to my requirements.
Does anyone know of any clear documentation on how to do this sort
of thing with core data? To summarise my problem, I'm trying to
list all available extras that can be attached to a domain using a
NSTableView with a checkbox column. If the user wants a domain to
have a certain feature, they simply check the box. The problem
(feature!) is that users can set up their own extras with
associated costs.
If I understand the issue correctly, this isn't really a Core Data
problem, it's an application architecture problem.
You can get all the objects for a given entity using an "unqualified"
fetch (that is, one that does not have a predicate).
You can get all the objects related to a given object simply by
"asking" it directly (see <http://developer.apple.com/documentation/
Cocoa/Conceptual/CoreData/Articles/cdFAQ.html>).
The real problem is how to set up a user interface that allows you to
manipulate these collections (in particular the latter), and there
isn't a simple answer to that. There are many approaches you can
take, and which you choose depends on what user interface you want to
present, and whether or not you want to use bindings.
If you want a to use a (single) table view that presents all the
objects of the given entity and a check box to indicate membership
(or otherwise) of a relationship, then it may be easiest to use an
NSArrayController to manage the entities, but use a standard table
view data source method to return and set the value of the checkbox.
The philosophy is akin to that discussed here:
<http://www.stepwise.com/Articles/Technical/WOF_Checkboxes.html>
The basis for another approach, using bindings and two table views,
is illustrated here:
<http://homepage.mac.com/mmalc/CocoaExamples/Groups.zip>
And the Core Recipes example illustrates a simpler approach using an
NSMatrix object and bindings:
<http://developer.apple.com/samplecode/CoreRecipes/
CoreRecipes.html>
mmalc
Example for Employee <<-->> Project
#import <Disclaimers/Standard.h>
2 array controllers, 1 for each entity.
Automatically prepares content set to YES, so kept up-to-date.
Employees table view bound to employeesArrayController.
MyDocument serves as data source for Projects table view.
@interface MyDocument : NSPersistentDocument {
IBOutlet NSArrayController *employeesArrayController;
IBOutlet NSArrayController *projectsArrayController;
IBOutlet NSTableView *projectsTableView;
}
@end
NSString *selectedEmployeeContext = @"selectedEmployeeContext";
@implementation MyDocument
- (id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
// find the managed object at index 'rowIndex'
NSArray *dataSourceArray = [projectsArrayController
arrangedObjects];
NSManagedObject *rowObject = [dataSourceArray
objectAtIndex:rowIndex];
NSString *identifier = [aTableColumn identifier];
if (![identifier isEqualToString:@"empOnProject"]) {
return [rowObject valueForKey:identifier];
}
NSArray *selectedObjects = [employeesArrayController
selectedObjects];
if ([selectedObjects count] != 1) {
return [NSNumber numberWithInt:-1]; // check box allows
mixed state
}
NSSet *sourceProjects = [[employeesArrayController selection]
valueForKey:@"projects"];
BOOL inDestination = [sourceProjects containsObject:rowObject];
return [NSNumber numberWithBool:inDestination];
}
- (void)tableView:(NSTableView *)aTableView
setObjectValue:(id)anObject
forTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
// find the managed object at index 'rowIndex'
NSArray *dataSourceArray = [projectsArrayController
arrangedObjects];
NSManagedObject *rowObject = [dataSourceArray
objectAtIndex:rowIndex];
NSString *identifier = [aTableColumn identifier];
if (![identifier isEqualToString:@"empOnProject"]) {
return [rowObject setValue:anObject forKey:identifier];
}
NSArray *selectedObjects = [employeesArrayController
selectedObjects];
if ([selectedObjects count] != 1) {
return;
}
NSMutableSet *sourceProjects = [[employeesArrayController
selection]
mutableSetValueForKey:@"projects"];
BOOL inDestination = [anObject boolValue];
if (inDestination) {
[sourceProjects addObject:rowObject];
}
else {
[sourceProjects removeObject:rowObject];
}
}
- (void)windowControllerDidLoadNib:(NSWindowController *)
windowController
{
[super windowControllerDidLoadNib:windowController];
[employeesArrayController addObserver:self
forKeyPath:@"selectedObjects"
options:nil
context:selectedEmployeeContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == selectedEmployeeContext) {
[projectsTableView reloadData];
return;
}
[super observeValueForKeyPath:keyPath ofObject:object
change:change context:context];
}
// ...
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden