【问题标题】:Performing multiplication (aggregation) with CoreData: how to?使用 CoreData 执行乘法(聚合):如何?
【发布时间】:2012-01-24 10:25:30
【问题描述】:

a fantastic tutorial by Jeff Lamarche 之后,我正在尝试为NSManagedObject 的特定子类聚合数据。

这就是场景。我创建了一个名为 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

【问题讨论】:

    标签: ios core-data nsmanagedobject nsmanagedobjectcontext nsfetchrequest


    【解决方案1】:

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

    代码如下:

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

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

    希望对你有帮助!

    【讨论】:

      【解决方案2】:

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

      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 是引用quantityprice 的表达式对的数组。 multiplyExpression 是表达式multiply:by:,参数为quantityPriceex 是您的 sum: 表达式,引用了引用数量和价格键路径的多个表达式。

      我很确定您会想要做类似的事情,但是如果没有像您这样的数据库设置等,我无法对其进行测试,所以这只是理论。

      【讨论】:

      • 感谢您的回复。运行它,代码停在NSArray *results = [context executeFetchRequest:request error:nil];,但有以下异常EXCEPTIONS: unwinding through frame有什么建议吗?
      • 您是否得到了我的编辑版本,我在 'multiply:by:' 表达式中添加了尾随 ':'? StackOverflow 给我解决了大约 10 分钟的麻烦。 :( 也就是说,堆栈跟踪中的某处应该有一个更全面的错误,类似于:Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error while updating. 'constraint failed'' 你能贴出完整堆栈跟踪的粘贴吗?
      • 是的,我做到了。堆栈跟踪显示该异常。我可以做些什么来查看完整的堆栈跟踪吗?我的方案项目中启用了日志异常。
      • 另一件有用的事情是编辑应用程序的运行方案,并将-com.apple.CoreData.SQLDebug 1(它可能需要作为两个单独的参数输入)添加到参数中。这将(在某些平台上)在针对数据库运行时触发 SQL 语句的核心数据转储到控制台。有时查看生成的 SQL 可以告诉您出了什么问题。
      • 当我的意思是“multiplyExpression”时,看起来我也写了“multipleExpression”。仍然,您在 XCode 中查看控制台视图,它给出的只是一行“展开框架”而没有额外的细节,或者如果您向上或向下滚动,它会提供任何东西?呃;这将使调试变得困难。确实应该有一个更深层次的“原因”。
      猜你喜欢
      • 2015-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-10
      • 2021-03-10
      • 2019-04-13
      • 2016-08-21
      • 2019-05-31
      相关资源
      最近更新 更多