Following a fantastic tutorial by Jeff Lamarche, I'm trying to aggregate data for a specific subclass of NSManagedObject
.
This is the scenario. I created a class named Product
that extends NSManagedObject
class. Product
class has three properties like the following:
@property (nonatomic, retain) NSString* name;
@property (nonatomic, retain) NSNumber* quantity;
@property (nonatomic, retain) NSNumber* price;
I also created a category, called Product+Aggregate
, where I perform a sum aggregation. In particular, following Jeff tutorial, I managed the sum for quantity attribute.
+(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;
}
This class method is called as follow from a specific UIViewController
:
NSNumber *totalQuantity = [Product aggregateOperation:@"sum:" onAttribute:@"quantity" withPredicate:nil inManagedObjectContext:self.context];
The code works well. In fact, if I have say 3 product
NAME QUANTITY PRICE
PRODUCT 1 2 23.00
PRODUCT 2 4 12.00
PRODUCT 3 1 2.00
The aggregateOperation
method returns 7 as expected.
Now I would have one more step. Modifying that method, I need to return the total cost for product order. In other words, I need to calculate QUANTITY*PRICE value for each product and finally return the TOTAL.
Could you suggest me the right way? Thank you in advance.
EDIT This is the new code I use after Cyberfox suggestion but unfortunately it doesn't work.
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
This is a shot in the dark, because to replicate your code I'd need to build a database, etc., but I believe that you want:
quantityPrice
is an array of the pair of expressions referring toquantity
andprice
.multiplyExpression
is the expressionmultiply:by:
with the parameters ofquantityPrice
.ex
is yoursum:
expression, referencing the multiple expression referencing the quantity and price key paths.I'm pretty sure you'd want to do something like that, but I can't test it without a DB set up like yours, etc., so it's just theory.
For those interested in, I found the solution for the problem above.
Here's the code:
P.S. to use it create a Class method that returns a
NSNumber
and accepts as parameters the managed context and 2 attributes (NSString
) where you want to perform data retrieving.Hope it helps!