user1904273
user1904273

Reputation: 4764

ios/xcode/coredata: Data model for many to many relationships

IOS newb from mysql background working on an app that ties into a web server backend. If I have two entities or objects enjoying many to many relationships such as item and tag, in MYSQL I would have three tables, the table of items, the table of tags and a third table of tag-item relationships.

Table 1 Tags ID|tag

Table 2 Items ID|item

Table 3 Tagitems ID|tagid|itemid

If I want to do this in core data would it be appropriate to also have three entities?

Entity 1: Tags id|tagname

Entity 2: Items id|itemname

Entity 3: Tagitems id|tagid|itemid

Seems straightforward enough but just want to make sure I am understanding core data correctly.

Upvotes: 1

Views: 141

Answers (1)

pbasdf
pbasdf

Reputation: 21536

If your intermediate table has no other attributes, then you do not need to model it yourself. Just create a to-many relationship from Entity 1 to Entity 2, and a to-many relationship from Entity 2 to Entity 1, and make each relationship the inverse of the other. CoreData will build and manage the intermediate table for you (and its existence is largely hidden from you). The model editor should look something like this:

enter image description here

When you generate subclasses, CoreData will create NSSet properties for the relationships:

Tag.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Item;

@interface Tag : NSManagedObject
@property (nonatomic, retain) NSString * tagName;
@property (nonatomic, retain) NSSet *items;
@end

@interface Tag (CoreDataGeneratedAccessors)
- (void)addItemsObject:(Item *)value;
- (void)removeItemsObject:(Item *)value;
- (void)addItems:(NSSet *)values;
- (void)removeItems:(NSSet *)values;
@end

Item.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Tag;

@interface Item : NSManagedObject
@property (nonatomic, retain) NSString * itemName;
@property (nonatomic, retain) NSSet *tags;
@end

@interface Item (CoreDataGeneratedAccessors)
- (void)addTagsObject:(Tag *)value;
- (void)removeTagsObject:(Tag *)value;
- (void)addTags:(NSSet *)values;
- (void)removeTags:(NSSet *)values;
@end

You can then use the core data generated accessors to add and remove relationships - note that you set the relationships directly between objects, you don't have to use IDs; CoreData is handling the IDs for you "in the shadows". So you could do something like this:

Tag *actionTag = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:self.context];
actionTag.name = @"Action";
Tag *dramaTag = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:self.context];
dramaTag.name = @"Drama";

Item *movie = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:self.context];
movie.name = @"Pride and Prejudice";
[movie addTagsObject:dramaTag];    

If your intermediate table does have other attributes, then you should implement Entity 3, and add whatever attributes you need (but do not implement the 'id' keys - leave that to CoreData). The relationships from Entity 1 to Entity 3 should be to-many, but its inverse should be to-one; likewise from Entity 2 to Entity 3 should be to-many, and its inverse to-one:

Entity 2 <---->> Entity 3 <<----> Entity 1

Upvotes: 1

Related Questions