所有实例属性的核心数据总和

Posted

技术标签:

【中文标题】所有实例属性的核心数据总和【英文标题】:Core Data sum of all instances attribute 【发布时间】:2013-02-11 23:06:19 【问题描述】:

使用Core Data,我遇到了一个问题。我有一个带有属性“数量”的实体“运动”。如何计算所有实例的所有“数量”的总和?我想了解NSExpressionDescription的使用方法,不过NSSet已经够用了。

【问题讨论】:

【参考方案1】:

拥有一个 managedObjectContext:

NSManagedObjectContext *managedObjectContext = ...

我们创建一个返回类型字典的获取请求:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([Movement class])];
fetchRequest.resultType = NSDictionaryResultType;

然后我们创建一个表达式描述来计算总和:

NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
expressionDescription.name = @"sumOfAmounts";
expressionDescription.expression = [NSExpression expressionForKeyPath:@"@sum.amount"];
expressionDescription.expressionResultType = NSDecimalAttributeType;

设置要获取的请求属性:

fetchRequest.propertiesToFetch = @[expressionDescription];

如果需要,我们也可以设置谓词。

最后我们执行请求并获得一个数组,其中包含一个带有一个键的字典 (@"sumOfAmounts"),它的值是一个带有金额总和的 NSNumber。

NSError *error = nil;
NSArray *result = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (result == nil)

    NSLog(@"Error: %@", error);

else

    NSNumber *sumOfAmounts = [[result objectAtIndex:0] objectForKey:@"sumOfAmounts"];

干杯

【讨论】:

@e1985 请提出一个问题:我要计算单个实例使用的总和:NSNumber *sum = [fund valueForKeyPath:@"fund_relativeMovement.@sum.amount"];,我也会为此使用您编写的相同机制。只是我不知道如何在表达式之前将实例设置为实体。谢谢! 喜欢这个!我将如何使用它来针对已排序的 fetchRequest 运行?我的表有 2 个部分,每个部分都有一组值。我想要每个部分的唯一总数。 这是否有效取决于所使用的持久存储的类型。虽然它在 SQLite 的支持下确实有效,但我无法让它与 NSInMemoryStoreType 一起使用。如果您收到[<NSDictionaryMapNode ...> valueForUndefinedKey:]: this class is not key value coding-compliant for the key @sum. 异常,这可能表明您的持久存储不支持此功能。 @TimBodeit,我没有用 NSInMemoryStoreType 测试它,但我想你是对的。过去,我发现不同类型的 CoreData 持久存储存在问题。在我的情况下,情况正好相反:在测试中在内存中工作的东西不是 SQLite。我最终在测试中也使用了 SQLite,以获得与实际生产代码相同的行为。【参考方案2】:

这是一个使用NSExpressionNSExpressionDescription 对托管对象的属性求和的Swift 示例。该示例假定托管对象名为 Movement 并且要求和的属性为 amount

示例:

 func sumAmount() -> Double 
    var amountTotal : Double = 0

    // Step 1:
    // - Create the summing expression on the amount attribute.
    // - Name the expression result as 'amountTotal'.
    // - Assign the expression result data type as a Double.

    let expression = NSExpressionDescription()
    expression.expression =  NSExpression(forFunction: "sum:", arguments:[NSExpression(forKeyPath: "amount")])
    expression.name = "amountTotal";
    expression.expressionResultType = NSAttributeType.doubleAttributeType

    // Step 2:
    // - Create the fetch request for the Movement entity.
    // - Indicate that the fetched properties are those that were
    //   described in `expression`.
    // - Indicate that the result type is a dictionary.

    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Movement")
    fetchRequest.propertiesToFetch = [expression]
    fetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType

    // Step 3:
    // - Execute the fetch request which returns an array.
    // - There will only be one result. Get the first array
    //   element and assign to 'resultMap'.
    // - The summed amount value is in the dictionary as
    //   'amountTotal'. This will be summed value.

    do 
        let results = try context.fetch(fetchRequest)
        let resultMap = results[0] as! [String:Double]
        amountTotal = resultMap["amountTotal"]!
     catch let error as NSError 
        NSLog("Error when summing amounts: \(error.localizedDescription)")
    

    return amountTotal


其他步骤讨论:

第 1 步 - 创建一个 NSExpressionDescription 变量。这个NSExpressionDescription 表示将什么类型的函数应用于参数。 sum 函数正在应用于 amount 属性。

expression.expression =  NSExpression(forFunction: "sum:", 
    arguments:[NSExpression(forKeyPath: "amount")])

请注意,arguments 参数是一个数组。您可以在数组中传递不同类型的表达式,但在我们的例子中,我们只需要 amount 属性。

第 2 步 - 获取请求在此处建立。请注意,结果类型被指定为字典:fetchRequest.resultType = NSAttributeType.DictionaryResultType。在第 3 步中,我们将使用 amountTotalexpression.name 值作为访问总和值的键。

第 3 步 - 我们执行获取请求并返回一个单元素数组。该元素将是一个字典,我们将其设为[String:Double]:let resultMap = results[0] as! [String:Double]。字典的值是 Double,因为在第 1 步中我们指出 expression.expressionResultType 将是 Double。

最后,我们通过调用与amountTotal 键关联的字典值来访问总和:resultMap["amountTotal"]!


参考资料:

NSExpression 和 NSExpressionDescription

【讨论】:

感谢您的详细说明,这应该被接受【参考方案3】:

最好的方法是使用fetch for specific values 并提供NSExpressionDescription with a sum: function.

当您执行 fetch 时,您会得到一个单元素数组,其中包含一个字典,其键与表达式描述匹配,其值是表达式的结果。在这种情况下,您将获得一个 sum 键,其值将是给定表达式的属性的总和。

【讨论】:

以上是关于所有实例属性的核心数据总和的主要内容,如果未能解决你的问题,请参考以下文章

核心数据实体中所有对象的属性总和

两个日期之间实体属性的核心数据总和

核心数据实体属性的总和数组

分组核心数据对象

使用核心数据计算多节表的总和

通过核心数据计算十进制值的总和不能正常工作?