Vikings
Vikings

Reputation: 2527

Core Data One-to-Many Relationship

I have a one-to-many relationship in my Core Data model. One meal can have multiple foods. I want to populate a table with the the foods from one meal. So if Meal #1 has Apples, Oranges, and Lemons, then the table would consist of those three foods.

Any help is very appreciated because I am completely stuck.

Here is my model:

enter image description here

And the NSManagedObject Classes:

Meal.h

@class Food;

@interface Meal : NSManagedObject

@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSSet *foods;

@end

@interface Meal (CoreDataGeneratedAccessors)

- (void)addFoodsObject:(Food *)value;
- (void)removeFoodsObject:(Food *)value;
- (void)addFoods:(NSSet *)values;
- (void)removeFoods:(NSSet *)values;

@end

Food.h

@class Meal;

@interface Food : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) Meal *meals;

@end

Here is the code where I cam trying to attempt this, but I am having some issues.

- (NSFetchedResultsController *)fetchedResultsController 
{    
    if (_fetchedResultsController != nil)
        return _fetchedResultsController;

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Food" inManagedObjectContext:_context];
    [fetchRequest setEntity:entity];

    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"Meal.foods == %@", entity]];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:_context sectionNameKeyPath:nil cacheName:@"Root"];

    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    [fetchRequest release];
    [theFetchedResultsController release];

    return _fetchedResultsController;      
}

Upvotes: 2

Views: 4873

Answers (2)

FluffulousChimp
FluffulousChimp

Reputation: 9185

You mention that you are having issues, but not what the issues are; but your NSFetchRequest predicate doesn't look right to me. Also meals defined on Food is plural but the relationship is To-one -- a little confusing.

Your UITableView should be populated with the Foods from a single Meal, right? Let's call that Meal _thisMeal, then the fetch predicate should be:

NSPredicate *foodPredicate = [NSPredicate predicateWithFormat:@"meals == %@",_thisMeal];
[fetchRequest setPredicate:foodPredicate];

So, the entity you're fetching is Food; and this predicate ensures that their meals property is the Meal your UITableViewController is looking for.

Updated to show how to fetch a named Meal

To fetch a Meal named "Custom Meal":

Meal *_thisMeal = nil;
// this assumes that there should be only one Meal named "Custom Meal"
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Meal"];
NSPredicate *fetchPredicate = [NSPredicate predicateWithFormat:@"name = %@",@"Custom Meal"];

NSError *fetchError = nil;
NSArray *meals = [_context executeFetchRequest:request error:&fetchError];
if( fetchError )
    NSLog(@"%s - ERROR while fetching Meal: %@,%@",__FUNCTION__,fetchError,[fetchError userInfo]);
else if( [meals count] != 0 )
    _thisMeal = [meals objectAtIndex:0];

Upvotes: 3

Gobot
Gobot

Reputation: 2480

Your Meal and Food classes are wrong. It's best to kill those and let XCode auto re-generate those classes via (make sure your entity is selected):

enter image description here

In your fetchedResultsController getter method, kill the line:

[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"Meal.foods == %@", entity]];

You would normally use a predicate to filter your data, such as foods that contain a banana. Your current predicate doesn't really make sense at the moment. It's saying "give me meals that contain a food called 'entity',...doesn't make sense.

Since you want to get meals...

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Food" inManagedObjectContext:_context]; 

should be:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Meal" inManagedObjectContext:_context];

(note the @"Meal").

You would then access the foods from each meal via meal.foods.

This line:
self.fetchedResultsController = theFetchedResultsController;
should be:
_fetchedResultsController = theFetchedResultsController;
What you did is basically call the method you are currently in.

Upvotes: 0

Related Questions