Search code examples
iphonecore-datansfetchedresultscontrollernspredicate

Core Data: Predicate that Returns Objects of Another Entity


I have two entities in my data model: Details and Lookup. I need find all Details objects related to a specific Lookup object that has specific attribute value and then return those Details objects via a fetched results controller.

My NSManagedObjectSubclasses:

@interface Details : NSManagedObject {
@privateI 
}
@property (nonatomic, retain) NSString * owner;
@property (nonatomic, retain) NSString * introduction;
@property (nonatomic, retain) NSString * id;
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSString * created;
@property (nonatomic, retain) NSString * modified;
@property (nonatomic, retain) NSNumber * type;
@property (nonatomic, retain) NSString * desc;


@interface Lookup : NSManagedObject {
@private
}
@property (nonatomic, retain) NSDate * search_date;
@property (nonatomic, retain) NSString * search_phrase;
@property (nonatomic, retain) NSSet* searchResults;

I need to find a Lookup object based on its search_phrase attribute and then get all the related Details objects and return those in a fetched results controller.

I think I have to search for the Lookup object first, then walk the NSSet of Detail objects but I do not know how to return those in the NSFetchedResultsController.

I've tried:

NSPredicate *predicate =[NSPredicate predicateWithFormat:@"search_phrase = %@", self.searchPhrase];

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

fetchRequest.predicate = predicate;

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Lookup" inManagedObjectContext:self.context];

[fetchRequest setEntity:entity];

NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"search_phrase" ascending:NO];

[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.context sectionNameKeyPath:nil cacheName:@"Searches"];

I have a request that finds the right Lookup object but I don't know how to get the related Detail objects from the fetched results controller.


Solution

  • Firstly, you don't have a reciprocal relationship defined between Details and Lookup but just a one-way Lookup to Details. You need to add a relationship to both the data model entity running from Detail to Lookup and have it set has the recipocal of Lookup.searchResults and your Detail class needs a property something like:

    @property (nonAtomic,retain) Lookup *lookup;
    

    Having a reciprocal relationship lets you find Detail objects by starting with a Lookup object and lets you find a Lookup object starting with a Detail object.

    If you want you tableview to display a list of Detail objects, then you need to configure the fetched results controller's fetch request to fetch against the Detail entity. As a rule of thumb, you always set the fetch request entity to the entity whose objects you wish to display in the tableview.

    The predicate likewise will be run against the Detail entity so you need a predicate that evaluates against a keypath that starts with a property of the Detail entity. In this case, we want all Details objects whose related Lookup object has a search_phase attribute equalling a provide value. So:

    NSPredicate *p=[NSPredicate predicateWithFormat:@"lookup.search_phrase==%@", self.searchPhrase];
    

    Now setup your fetch request thusly:

      NSFetchRequest *fetch=[[NSFetchRequest alloc] init];
      NSEntityDescription *detailsEntity=[NSEntityDescription entityForName:@"Details" inManagedObjectContext:self.context];
      [fetch setEntity:detailsEntity];
      [fetch setPredicate:p];
      //.. set up a sort however you want the details to appear in the tableview
    

    Give this fetch to your NSFetchedResultsController and it will return the Detail objects you are looking for.

    In summary:

    • Always use reciprocal relationships in a data model so you can have flexibility.
    • When using a fetched results controller, set the entity of the fetch request to the entity whose objects you wish to appear in the tableview.