I am needing to do a “join”-type operation on two tables/models from my Core Data storage, and I’m having a difficult time finding good examples out there for getting something like this to work.
It’s fairly simple what I need to do. I have two models/tables: locations and location_categories, where locations contains a location/establishment’s details (along with a unique ID), and the location_categories table contains category_id’s with associated location_id’s. I need to select all the locations where, given a category_id, it joins the two tables/models. If it was straight SQL, it would look like this (and this query does work when I run it against the actual SQLite DB):
// pretend we passed in a catID of 29:
SELECT * FROM zlocation where zlocid in (select zlocid from zloccategory where zcatid = 29)
So as you can see, it’s pretty straight-forward. Is there a way to do this without having to do two fetches and for-loops? My current objective-c code to do this is below, and it works fine, but of course it’s horribly slow and inefficient, due to a lot of data being in both tables. The for-loops are causing a huge slowdown, and my gut tells me that this work really should be done on the DB/Core-Data side of things:
- (NSMutableArray *) fetchLocsWithCatID:(NSString *)catID {
NSMutableArray *retArr = [[NSMutableArray alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:MODELNAME_LOCCATEGORIES inManagedObjectContext:context]];
[fetchRequest setPredicate: [NSPredicate predicateWithFormat:@"catID == %@", catID]];
NSError *error;
NSArray *locCats = [context executeFetchRequest:fetchRequest error:&error];
NSArray *allLocsArr = [self fetchAllDataForTable:MODELNAME_LOCATION]; // this retrieves contents of entire table
for (Location *currLoc in allLocsArr) {
for (LocCategory *currLocCat in locCats) {
if ([currLoc.locID isEqualToString:currLocCat.locID]) {
if (![retArr containsObject:currLoc]) {
[retArr addObject:currLoc];
}
}
}
}
return retArr;
}
Any thoughts on whether this is possible with one single predicate/fetch? Or dunno.. maybe there is a more efficient way to join those two NSArrays via the objective-c code?
Thanks in advance for any direction you can offer on this!
The best way would be to use relationships.
This way when you fetch a
Locationyou can also access theLocationCategorylikemyLocation.locationCategoryYou would need to set up your relationsship like so:
It’s a to-many relationship. Don’t forget the inverse either.
Once that’s set up you just need to connect relationships up where ever you create the entity instances. Like:
Also make sure you are using the same MOC to fetch the objects. I strongly recommend MagicalRecord to easily manage creating objects and fetching in the specified moc.