所有实例属性的核心数据总和
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】:
这是一个使用NSExpression
和NSExpressionDescription
对托管对象的属性求和的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 步中,我们将使用 amountTotal
的 expression.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
键,其值将是给定表达式的属性的总和。
【讨论】:
以上是关于所有实例属性的核心数据总和的主要内容,如果未能解决你的问题,请参考以下文章