开发者

Calculating sum for decimal values via Core Data not working properly?

first time I post to this round, so please bear with me if I don't follow all the rules properly.

I am writing an app for the iPhone (OS 3.1) and am trying to write some code which lets me add decimals. I have a Core Data entity called SimpleItem with a amount attribute. Here is the test case I wrote:

// Create and configure objects
    SimpleItem *si1 = [self createSimpleItem:@"si1"];
    si1.amount = [NSDecimalNumber decimalNumberWithMantissa:1000 exponent:0 isNegative:NO];
    SimpleItem *si2 = [self createSimpleItem:@"s12"];
    si2.amount = [NSDecimalNumber decimalNumberWithMantissa:2000 exponent:0 isNegative:NO];
    // Need to save prior to fetching results with NSDictionaryResultType (known limitation)
    [self save]; 

    // Describe fetch request
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entityDescription = [NSEntityDe开发者_开发知识库scription entityForName:@"SimpleItem" inManagedObjectContext:self.context];
    [request setEntity:entityDescription];
    [request setResultType:NSDictionaryResultType];

    NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"amount"];
//  For whatever reason, evaluating this expression here is absolutely not working. Probably decimals aren't handled properly.
    NSExpression *sumAmountExpression = [NSExpression 
                                         expressionForFunction:@"max:"
                                         arguments:[NSArray arrayWithObject:keyPathExpression]];

    NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
    [expressionDescription setName:@"amount"];
    [expressionDescription setExpression:sumAmountExpression];
    [expressionDescription setExpressionResultType:NSDecimalAttributeType];
    [request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];

    // Fetch the amounts
    NSError *error = nil;
    NSArray *array = [self.context executeFetchRequest:request error:&error];

If I execute this code through otest and debug it, I get an exception when the fetch request is executed: "-[NSDecimalNumber count]: unrecognized selector sent to instance."

Just evaluating the keyPathExpression without the aggregate function works fine, though.

The reference documentation shows exactly the same example so I'm wondering what I am doing wrong. Or could this be just a bug?

All the best, Harald


Copying your given source to a new iPhone project and running that in the simulator worked fine here. I was compiling against the 3.1.2 SDK on Snow Leopard.

This is what I used for the data model:

model description http://homepage.mac.com/aclark78/.Public/Pictures/test%20model.png

There must be something else going on causing your issue. Can you describe your model or simplify it further?


I think I had this problem before. IIRC, the problem is that you've set your fetch result type to NSDictionaryResultType but you're receiving it in an NSArray. Try switching the fetch result type to NSManagedObjectResultType which does return an array. All the examples in the docs use the default NSManagedObjectResultType.

In any case, the error message clearly results from an NSDecimal object being sent an array's count message. You could confirm this by trapping the result in an id. eg:

id *genericObj = [self.context executeFetchRequest:request error:&error];  
NSLog("returned object=%@",genericObj);
NSLog("returned object class=%@",[genericObj class]);


Thanks for letting me know. The thing is that I actually don't want to use managed objects. After all, I am interested in the amounts only and this is what I get with the dictionary.

Also, trying to investigate the issue as you described didn't work as executing the fetch request immediately fails and I don't get anything back.

Any other ideas? Is there any other possibility to get aggregate values? Any "best practices"? At the moment I do the following (continuation of the code above):

NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init]; [expressionDescription setName:@"amount"]; [expressionDescription setExpression:keyPathExpression]; [expressionDescription setExpressionResultType:NSDecimalAttributeType]; [request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];

// Fetch the amounts
NSError *error = nil;
NSArray *array = [self.context executeFetchRequest:request error:&error];
if (array == nil) {
    STFail(@"Fetch request could not be completed: %@", [error localizedDescription]);
}
STAssertEquals([array count], (NSUInteger) 2, @"Number of fetched objects != 2");

// Manually calculate the sum
NSDecimalNumber *sum = nil;
for (NSDictionary * dictionary in array) {
    NSDecimalNumber *amount = (NSDecimalNumber *) [dictionary valueForKey:@"amount"];
    if (!sum) {
        sum = amount;
    } else {
        sum = [sum decimalNumberByAdding:amount];
    }
}
STAssertNotNil(sum, @"Sum is nil");
STAssertTrue([sum isEqualToNumber:[NSDecimalNumber decimalNumberWithMantissa:3000 exponent:0 isNegative:NO]], 
               @"Sum != 3000: %@", sum);

Regards, Harald

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜