如何计算与一对多关系的查询匹配的核心数据实体?

时间:2013-04-08 04:41:48

标签: ios core-data count group-by entity

假设我有2个核心数据实体。学生实体和类实体。对于这个例子,一个学生只有一个班级,一个班级可以有很多学生。

我们也假设这些都是大班。也就是说,每个班级都有1000名学生。

Class实体如下:

NSString* name
NSArray* students

和学生实体:

NSString* name
Class* class
NSString* grade

在我的UI中,我想要显示一个类。我想展示具有一定年级的学生的数字。即对于一个1000名学生,50人有A,500人有B的200人有C ......等等。

从Core Data获取这些数据的最有效方法是什么?

我是最新的;使用NSFetchedResultsController并通过+ count查询传递一个组的获取请求。我正在使用NSFetchedResultsController,以便UI更新为具有某个等级更改的学生数量。但它很慢。

有没有办法在不查询的情况下获取此信息?即当学生被添加到课程中或他们的成绩发生变化时,课程中的属性会更新所有成绩计数。因此,当我想要计数时,它们只是类的属性,不需要查询。

有可能吗?

3 个答案:

答案 0 :(得分:9)

您可以尝试此获取请求:

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Student"];
[request setResultType:NSDictionaryResultType];
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"grade"];
NSExpression *countExpression = [NSExpression expressionForFunction:@"count:" arguments:[NSArray arrayWithObject:keyPathExpression]];

NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:@"gradeTypeCount"];
[expressionDescription setExpression:countExpression];
[expressionDescription setExpressionResultType:NSInteger64AttributeType];
[request setPropertiesToFetch:@[@"grade",expressionDescription]];
[request setPropertiesToGroupBy:@[@"grade"]];
[request setPredicate:[NSPredicate predicateWithFormat:@"theClass == %@",cls.objectID]];

这将导致一组字典保持所需的值 这里的问题是你的FRC无法跟踪这些结果的变化。因此没有理由首先使用FRC 即便如此,这是一个非常轻量级的请求,您可以在给定的时间间隔发出它并更新您的UI。

  
    

(比如说2秒,因为你不再处理托管对象,你可以在后台完成整个过程并将结果转储到主线程中)你的身份。

  

或者对主要上下文的更改持续存在,如果学生元素发生变化,您将再次重新获取计数。

这将避免一起提取任何Student个元素(按描述的成本)。

答案 1 :(得分:5)

您可以使用以下示例在给定条件下获取计数。您无需获取数据进行计数。您可以使用countForFetchRequest方法有效地计算对象。

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:moc]];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:
        @"grade=='A'"];
    [request setPredicate:predicate];

    NSError *err;
    NSUInteger count = [moc countForFetchRequest:request error:&err];
    if(count == NSNotFound) {
      //Handle error
    }

    [request release];

答案 2 :(得分:0)

在swift中非常简单。

let request = NSFetchRequest(entityName: "BWCoreDataNotification")
request.predicate = NSPredicate(format: "type = 'purchase_reward'")

var error: NSError?
let numberOfNotifications = NSManagedObjectContext.MR_defaultContext().countForFetchRequest(request, error: &error)