核心数据 - 简单的JOIN类型获取

时间:2012-12-06 22:29:23

标签: iphone objective-c ios core-data

我需要在我的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?

提前感谢您提供的任何方向!

3 个答案:

答案 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对象