我需要在我的Core Data存储中的两个表/模型上执行“join”类型的操作,而我很难找到好的例子来获得这样的东西。
我需要做的事情相当简单。我有两个模型/表:locations和location_categories,其中locations包含位置/企业的详细信息(以及唯一的ID),location_categories表包含category_id和关联的location_id。我需要选择所有位置,给定category_id,它连接两个表/模型。如果它是直接的SQL,它看起来像这样(当我针对实际的SQLite DB运行它时,这个查询确实有效):
// pretend we passed in a catID of 29:
SELECT * FROM zlocation where zlocid in (select zlocid from zloccategory where zcatid = 29)
你可以看到,这很简单。有没有办法做到这一点,而不必做两个提取和for循环?我目前的目标-c代码如下所示,它工作正常,但由于两个表中有大量数据,它当然非常慢且效率低下。 for循环导致了一个巨大的减速,我的直觉告诉我,这项工作确实应该在DB / Core-Data方面完成:
- (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;
}
有关使用单个谓词/提取是否可行的任何想法?或者dunno ..也许有更有效的方法通过objective-c代码加入这两个NSArray?
提前感谢您提供的任何方向!
答案 0 :(得分:4)
最好的方法是使用关系。
这样,当您提取Location
时,您也可以访问LocationCategory
myLocation.locationCategory
您需要像这样设置您的关系:
(Entity)LocationCategory.(relationship)locations <->> (Entity)Location.(relationship)locationCategory
这是一种多对多的关系。不要忘记逆转。
一旦设置完毕,您只需要在创建实体实例的地方连接关系。像:
Location *myLocation = ...
LocationCategory *myLocationCategory = ...
myLocation.locationCategoy = myLocationCategory;
还要确保使用相同的MOC来获取对象。我强烈建议MagicalRecord轻松管理创建对象并在指定的moc中获取。
答案 1 :(得分:2)
了解核心数据和关系。它将自动创建相关实体的其他对象集。因此,在您的上述情况下,如果您将Locations作为一个实体,Location_Categories作为另一个类别,您需要做的就是在Locations表中创建一个指向Location Categories实体的关系。
您可以在核心数据建模屏幕中执行此操作。
执行此操作后,Location Managed Object类将具有NSSet of Location Categories。同样,位置类别实体将在其中包含位置对象。
所以你需要做的只是一个位置类别查询,就像你上面的做法一样。但是,您需要执行
而不是执行其他查询for (LocationCategory *locationCategory in locationCats) {
NSLog(@"Location name is %@",locationCategory.location.locationName);
// You can ofcourse add it to an arrary or what ever
}
任何核心数据教程都应该能够为您提供帮助。
答案 2 :(得分:1)
如果这些实体在CoreData中建模,您通常会有一个从location_categories到位置的关联,并且从location到location_categories具有反向关系。因此,如果我有一个名为“Location”的实体,它将在其中建立一个名为locationCategory的关系,而在LocationCategory实体中,它将具有一个名为Location的关系。
在定义了这种双向关系之后,我会使用以下内容设置我的获取请求:
[fetchRequest setEntity:[NSEntityDescription entityForName:MODELNAME_LOCATIONS inManagedObjectContext:context]];
[fetchRequest setPredicate: [NSPredicate predicateWithFormat:@"locationCategory.catID == %@", catID]];
这应该返回与具有给定类别ID的位置类别相关联的所有Location对象