sash
sash

Reputation: 15

how to fetch data from two tables in core data objective-c

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

Answers (2)

Koushik Ravikumar
Koushik Ravikumar

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

pbasdf
pbasdf

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

Related Questions