Reputation: 15
I'm new in use Core Data. I have a two entities CDContact and CDAddress. I have problem to fetch a second entity (CDAddress).
self.fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"CDContact"];
[self.fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"firstName" ascending:YES]]];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:self.fetchRequest managedObjectContext:[CoreDataManager sharedInstance].managedObjectContext sectionNameKeyPath:nil cacheName:nil];
[self.fetchedResultsController setDelegate:self];
[self fetchResults];
It works but I get only data from CDContact.
I try something like this (I found this on documentation):
NSManagedObjectContext *context = [CoreDataManager sharedInstance].managedObjectContext;
NSEntityDescription *contactEntity = [NSEntityDescription entityForName:@"CDContact" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = contactEntity;
request.relationshipKeyPathsForPrefetching = [NSArray arrayWithObject:@"CDAddress"];
but in this version both entities doesn't work.
I'll be glad for any examples which help me resolve this problem.
Upvotes: 0
Views: 1541
Reputation: 706
The answer provided by pbasdf is perfect and very detailed. However, I would like to add this from the apple documentation.
To retrieve data using a managed object context, you create a fetch request. A fetch request is an object that specifies what data you want, for example, “all Employees,” or “all Employees in the Marketing department ordered by salary, highest to lowest.” A fetch request has three parts. Minimally it must specify the name of an entity (by implication, you can only fetch one type of entity at a time). It may also contain a predicate object that specifies conditions that objects must match and an array of sort descriptor objects that specifies the order in which the objects should appear...
Assuming the relationship between the entities CDContact and CDAddress is one-to-one, your CDContact interface file should look something like this:
@interface CDContact : NSManagedObject
@property (nonatomic,strong) NSString *firstName;
@property (nonatomic,strong) NSString *lastName;
@property (nonatomic,strong) CDAddress *address;
@end
This way, once you fetch a given CDContact object, you can access the related CDAddress object using the property "address". But if you need to access all addresses and all contacts, you need to perform two separate fetches.
Upvotes: 0
Reputation: 21536
As per comments, a fetch will only return results from a single entity. To access the second entity, you either need to run a second fetch, or to use the relationship on your CDContact
objects. For example if the relationship is named address
,
myCDContact.address
will give the CDAddress
for the specified CDContact
.
To expand on this, suppose your CDContact
entity has attributes firstName
and lastName
, and a one-one relationship to CDAddress
entitled address
. Likewise suppose your CDAddress
entity has attributes street
, town
, and zipCode
, and the inverse relationship to CDContact
entitled contact
.
Then to create a new contact named "John Smith" living at "1 Main Street, AnyTown, 90210", you would have code something like this:
CDContact *myCDContact = (CDContact *)[NSEntityDescription insertNewObjectForEntityForName:@"CDContact" inManagedObjectContext:context];
myCDContact.firstName = @"John";
myCDContact.lastName = @"Smith";
CDAddress *myCDAddress = (CDAddress *)[NSEntityDescription insertNewObjectForEntityForName:@"CDAddress" inManagedObjectContext:context];
myCDAddress.street = @"1 Main Street";
myCDAddress.town = @"AnyTown";
myCDAddress.zipCode = @"90210";
// and lastly, to set the relationship between them...
// EITHER
myCDContact.address = myCDAddress;
// OR
myCDAddress.contact = myCDContact;
(Note the either/or: you only have to set the relationship "one-way", CoreData will set the inverse automatically). If you then save the context, and subsequently fetch the contacts, with something like this:
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:@"CDContact"];
[fetch setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"firstName" ascending:YES]]];
NSError *error;
NSArray *results = [context executeFetchRequest:fetch error:&error];
then (assuming the fetch is successful: you should test for nil/error) the array will contain your contacts. Taking the first item in the array, you can then access its properties including the related CDAddress like this:
CDContact *myContact = (CDContact *)[results objectAtIndex:0];
NSLog(@"The contact is %@ %@", myContact.firstName, myContact.lastName);
NSLog(@"who lives at %@, %@, %@", myContact.address.street, myContact.address.town, myContact.address.zipCode);
(All the above assumes you have created NSManagedObject
subclasses for your entities. If you haven't, you should.)
Upvotes: 1