2013-04-08 64 views
3

可以说我有2个核心数据实体。学生实体和类实体。对于这个例子,一个学生只有一个班,一个班可以有很多学生。如何计算核心数据实体匹配查询一对多关系?

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

的实体类的样子:

NSString* name 
NSArray* students 

和学生实体:

NSString* name 
Class* class 
NSString* grade 

在我的UI,我想显示的类。我想显示号码有一定年级的学生。即对于一个1000名学生的班级,50个有A,500个有B的200个有C的......等等。

什么是从核心数据中获得这些计数的最有效方法?

我是最新的; y使用NSFetchedResultsController并通过+ count查询向其传递一个组的获取请求。我正在使用NSFetchedResultsController,以便UI随着具有特定等级的学生数量而更新。虽然这很慢。

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

可能吗?

回答

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秒,因为你不与被管理对象处理任何你可以做更多的全过程在后台为你倾倒你的结果在主线程请)

或者在您的主​​要环境中发生变化,并且如果学生元素发生变化,您将再次重新计数。

这样可以避免将所有元素全部集中在一起(以所描述的成本)。

+0

来尝试这种方法。 – aloo 2013-04-08 17:33:58

+0

如果您使用FRC,请添加排序描述符。 – 2013-04-08 18:07:59

+0

我最后只是使用您提供的提取请求使用该组,然后列出了对moc的更改,以便在需要时再次运行请求 – aloo 2013-04-08 21:03:43

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]; 
+0

如何监控这些计数的变化?此外,countForFetchRequest与常规提取的性能特点是什么? – aloo 2013-04-08 05:18:23

+0

您可以使用NSFetchrequstcontroller作为与fetchrequestcontroller相同的countForRetchRequest。这比普通提取更有效。你没有获取所有数据来获得计数。 – 2013-04-08 05:34:25

+0

我不认为在NSFetchedResultsController中有一个方法countForFetchRequest – aloo 2013-04-08 06:27:55

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)