4

正在关注a fantastic tutorial by Jeff Lamarche,我试图为NSManagedObject的特定子类汇总数据。使用CoreData执行乘法(聚合):如何?

这是场景。我创建了一个名为Product的类,它扩展了NSManagedObject类。 Product类有三个属性,如下列:

@property (nonatomic, retain) NSString* name; 
@property (nonatomic, retain) NSNumber* quantity; 
@property (nonatomic, retain) NSNumber* price; 

我还创建了一个类别,被称为Product+Aggregate,我在那里执行和聚集。特别是,按照Jeff的教程,我管理数量属性的总和。

+(NSNumber *)aggregateOperation:(NSString *)function onAttribute:(NSString *)attributeName withPredicate:(NSPredicate *)predicate inManagedObjectContext:(NSManagedObjectContext *)context 
{ 
    NSString* className = NSStringFromClass([self class]); 

    NSExpression *ex = [NSExpression expressionForFunction:function 
     arguments:[NSArray arrayWithObject:[NSExpression expressionForKeyPath:attributeName]]]; 

    NSExpressionDescription *ed = [[NSExpressionDescription alloc] init]; 
    [ed setName:@"result"]; 
    [ed setExpression:ex]; 
    [ed setExpressionResultType:NSInteger64AttributeType]; 

    NSArray *properties = [NSArray arrayWithObject:ed]; 
    [ed release]; 

    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    [request setPropertiesToFetch:properties]; 
    [request setResultType:NSDictionaryResultType]; 

    if (predicate != nil) 
     [request setPredicate:predicate]; 

    NSEntityDescription *entity = [NSEntityDescription entityForName:className 
     inManagedObjectContext:context]; 
    [request setEntity:entity]; 

    NSArray *results = [context executeFetchRequest:request error:nil]; 
    NSDictionary *resultsDictionary = [results objectAtIndex:0]; 
    NSNumber *resultValue = [resultsDictionary objectForKey:@"result"]; 

    return resultValue; 
} 

该类方法被称为如下从特定UIViewController

NSNumber *totalQuantity = [Product aggregateOperation:@"sum:" onAttribute:@"quantity" withPredicate:nil inManagedObjectContext:self.context]; 

代码工作得很好。事实上,如果我说3产品

NAME   QUANTITY  PRICE 
PRODUCT 1 2    23.00 
PRODUCT 2 4    12.00 
PRODUCT 3 1    2.00 

aggregateOperation方法返回7按预期。

现在我会再来一步。修改该方法,我需要返回产品订单的总成本。换句话说,我需要为每个产品计算QUANTITY * PRICE值,最后返回TOTAL。

你能告诉我正确的方法吗?先谢谢你。

编辑这是Cyber​​fox建议后使用的新代码,但不幸的是它不起作用。

NSString* className = NSStringFromClass([self class]); 

NSArray *quantityPrice = [NSArray arrayWithObjects: [NSExpression expressionForKeyPath:@"quantity"], [NSExpression expressionForKeyPath:@"price"], nil]; 

NSArray *multiplyExpression = [NSArray arrayWithObject:[NSExpression expressionForFunction:@"multiply:by:" arguments:quantityPrice]]; 

NSExpression *ex = [NSExpression expressionForFunction:function arguments:multiplyExpression]; 

NSExpressionDescription *ed = [[NSExpressionDescription alloc] init]; 
[ed setName:@"result"]; 
[ed setExpression:ex]; 
[ed setExpressionResultType:NSInteger64AttributeType]; 

// same as before 

回答

5

对于那些感兴趣的,我找到了上述问题的解决方案。

下面的代码:

static NSString* exprName1 = @"val1"; 
static NSString* exprName2 = @"val2"; 

NSString *className = NSStringFromClass([self class]); 

NSExpression *quantityPathExpression = [NSExpression expressionForKeyPath:firstAttribute]; //e.g. quantity  
NSExpression *unitaryPricePathExpression = [NSExpression expressionForKeyPath:secondAttribute]; //e.g. price 

NSExpressionDescription *quantityED = [[NSExpressionDescription alloc] init]; 
[quantityED setName:exprName1]; 
[quantityED setExpression:quantityPathExpression]; 
[quantityED setExpressionResultType:NSDictionaryResultType];  

NSExpressionDescription *unitaryPriceED = [[NSExpressionDescription alloc] init]; 
[unitaryPriceED setName:exprName2]; 
[unitaryPriceED setExpression:unitaryPricePathExpression]; 
[unitaryPriceED setExpressionResultType:NSDictionaryResultType]; 

NSArray *properties = [NSArray arrayWithObjects:quantityED, unitaryPriceED, nil]; 
[quantityED release]; 
[unitaryPriceED release]; 

NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
[request setPropertiesToFetch:properties]; 
[request setResultType:NSDictionaryResultType]; 

if (predicate != nil) 
    [request setPredicate:predicate]; 

NSEntityDescription *entity = [NSEntityDescription entityForName:className inManagedObjectContext:context]; 
[request setEntity:entity]; 

NSError* error = nil; 
NSArray *results = [context executeFetchRequest:request error:&error]; 

if(error != nil) 
{ 
    NSLog(@"An error occurred: %@", [error localizedDescription]); 
    abort(); 
} 

float total = 0; 
for (NSDictionary *resultDict in results) 
{ 
    NSNumber* quantityNumber = [resultDict valueForKey:exprName1]; 
    NSNumber* unitaryPriceNumber = [resultDict valueForKey:exprName2]; 

    int moltVal = [quantityNumber intValue]*[unitaryPriceNumber intValue]; 

    total += moltVal; 
}  

return [NSNumber numberWithInt:total]; 

附:使用它创建一个Class方法,该方法返回一个NSNumber并接受管理上下文作为参数,并接受要执行数据检索的2个属性(NSString)。

希望它有帮助!

0

这是一个在黑暗中拍摄,因为要复制你的代码我需要建立一个数据库,等等,但我相信,你想:

NSArray *quantityPrice = [NSArray arrayWithObjects: 
          [NSExpression expressionForKeyPath:@"quantity"], 
          [NSExpression expressionForKeyPath:@"price"], nil]; 
NSArray *multiplyExpression = [NSArray arrayWithObject:[NSExpression expressionForFunction:@"multiply:by:" arguments:quantityPrice]]; 
NSExpression *ex = [NSExpression expressionForFunction:function arguments:multiplyExpression]; 

quantityPrice是一个数组这一对表达方式指的是quantitypricemultiplyExpression是具有参数quantityPrice的表达式multiply:by:ex是您的sum:表达式,引用引用数量和价格关键路径的多重表达式。

我很肯定你会想做那样的事情,但是如果没有像你的那样设置数据库,我就无法测试它,所以这只是理论。

+0

谢谢您的回复。运行它,代码停止在'NSArray * results = [context executeFetchRequest:request error:nil];'有以下例外情况** EXCEPTIONS:通过框架展开**任何建议? –

+0

你有没有得到我编辑的版本,我添加了尾随的':'到'multiply:by:'表达式? StackOverflow给我解决了大约10分钟的麻烦。 :( 也就是说,在堆栈跟踪中应该有一个更全面的错误,其内容如下:'由于未捕获的异常'NSInternalInconsistencyException'终止应用程序,原因:'更新时出错'约束失败''Can你把一个完整的堆栈跟踪pastie? – Cyberfox

+0

是的,我做了。stacktrace呈现异常。我可以做一些事情看到一个完整的堆栈跟踪?我的方案项目中启用日志异常 –