Reputation: 1240
I have just started learning how to implement Core Data Model on the iOS. After some basic tutorials on how to store and retrieve data with one to one relationship among entities, I am now trying to implement a one to many relationship. My data model consists of two entities with their respective classes defined as follows:
Restaurant:
@interface Restaurant :NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSMutableArray *user_reviews; /* One to Many Relation to Review Entity*/
@end
Review:
@interface Review : NSObject
@property (nonatomic, strong) NSString *rating;
@property (nonatomic, strong) NSString *review_text;
@property (nonatomic, strong) User *user;
@end
I found similar questions that used NSMutableSet to insert, but I am unable to implement the same for an NSMutable Array.
Currently my insertion code looks like :
NSManagedObjectContext *context = [self managedObjectContext];
Restaurant *rest = [NSEntityDescription insertNewObjectForEntityForName:@"Restaurant" inManagedObjectContext:context];
rest.name = restaurant.name;
I retrieve the data for Restaurant and its Reviews via JSON and store them in temporary classes before saving them to the CORE Database. How do I insert such data which has One to Many Relationship ?
EDIT : Currently I receive the data in the form of a class which defines the user_review property as
NSMutableArray *user_reviews;
I am trying to implement this same class to insert into core data model. But the core data model uses NSSet instead of NSMutableArray. One brute approach is to duplicate all the classes with the same properties except instead of using NSMutableArray, i change it to NSSet. But this creates a huge amount of redundant code. Shouldn't there be a more efficient way to do this ?
Upvotes: 13
Views: 16618
Reputation: 1791
if your Review shall be a relationship in your coreDataModel, please use instead of NSMutableArray
the NSSet
and connect it with the Restaurant Entity.
In Review:
In Restaurant:
If you let xcode generate your class, it will look like this:
Restaurant:
@interface Restaurant : NSManagedObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSSet *user_reviews; /* One to Many Relation to Review Entity*/
@interface Restaurant(CoreDataGeneratedAccessors)
- (void)addUser_reviewsObject:(Review *)value;
- (void)removeUser_reviewsObject:(Review *)value;
- (void)addUser_reviews:(NSSet *)value;
- (void)removeUser_reviews:(NSSet *)value;
@end
Review:
@interface Review : NSManagedObject
@property (nonatomic, strong) NSString *rating;
@property (nonatomic, strong) NSString *review_text;
@property (nonatomic, strong) User *user;
@property (nonatomic, strong) Restaurant *restaurant;
@end
Your call will be:
NSManagedObjectContext *context = [self managedObjectContext];
Restaurant *rest = [NSEntityDescription insertNewObjectForEntityForName:@"Restaurant" inManagedObjectContext:context];
rest.name = restaurant.name;
Review *rev = [NSEntityDescription insertNewObjectForEntityForName:@"Review" inManagedObjectContext:context];
rev.rating = @"1";
rev.review_text = @"nomnomnom";
[rest addUser_reviewsObject:rev];
// or rev.restaurant = restaurant; one of both is enought as far as I remember
// save your context
edit
If it has to be a NSMutableArray
, it cannot be a ralation.
Those are always NSSets
(if x to n) or the destination classes. Using NSMutableArray
takes the advantages of sets and the automatic handling.
But if you realy want to store in NSMutableArray
, I recommand to expand your Review
class at least by a reviewID
attribute (unique) and store the NSMutableArray
as Transformable
.
//Review:
@interface Review : NSManagedObject
@property (nonatomic, strong) NSString *rating;
@property (nonatomic, strong) NSString *review_text;
@property (nonatomic, strong) User *user;
@property (nonatomic, strong) NSNumber *reviewID;
@end
//Restaurant.h:
@interface Restaurant : NSManagedObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSSet *user_reviews; // Set of NSNumbers
- (void)addUser_reviewsObject:(Review *)value;
- (void)addUser_reviewsID:(NSNumber *)value;
- (void)removeUser_reviewsObject:(Review *)value;
- (void)addUser_reviews:(NSMutableArray *)value;
- (void)removeUser_reviews:(NSMutableArray *)value;
@end
//Restaurant.m:
- (void)addUser_reviewsObject:(Review *)value
{
[self addUser_reviewsID:value.reviewID];
}
- (void)addUser_reviewsID:(NSNumber *)value
{
if(![self.user_reviews containsObject:value];
[self.user_reviews addObject:value];
}
- (void)removeUser_reviewsObject:(NSNumber *)value
{
// follow upper logic and implement yourself
}
- (void)addUser_reviews:(NSMutableArray *)value
{
// follow upper logic and implement yourself
}
- (void)removeUser_reviews:(NSMutableArray *)value
{
// follow upper logic and implement yourself
}
Upvotes: 22
Reputation: 357
Review *review = (Review *)[NSEntityDescription insertNewObjectForEntityForName:@"Review" inManagedObjectContext:[self managedObjectContext]];
review.review_text = @"test text";
//set other properties if needed
rest.user_reviews = [NSSet setWithObjects:review, nil];//just make NSSet for you reviews
Upvotes: 1