Performing Multiplication (Aggregation) Using CoreData: How?

Following Jeff Lamarch's fantastic tutorial , I am trying to aggregate data for a specific subclass of NSManagedObject .

This is the script. I created a class called Product that extends the NSManagedObject class. Product class has three properties, such as:

 @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 am aggregating the amount. In particular, following Jeff's study guide, I managed to get the amount for the 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 the following: UIViewController :

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

The code works well. In fact, if I say that 3 products

 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 will have one more step. By changing this method, I need to return the total cost of the product order. In other words, I need to calculate the QUANTITY * PRICE value for each product and finally return TOTAL.

Could you suggest me the right way? Thank you in advance.

EDIT This is the new code that I use after the Cyberfox suggestion, but unfortunately it does not 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 
+4
source share
2 answers

For those interested, I found a solution to the problem above.

Here is the code:

 static NSString* exprName1 = @"val1"; static NSString* exprName2 = @"val2"; NSString *className = NSStringFromClass([self class]); NSExpression *quantityPathExpression = [NSExpression expressionForKeyPath:firstAttribute]; //eg quantity NSExpression *unitaryPricePathExpression = [NSExpression expressionForKeyPath:secondAttribute]; //eg 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]; 

PS , to use it, create a class method that returns NSNumber , and takes as a parameter a managed context and 2 attributes ( NSString ), where you want to perform data extraction.

Hope this helps!

+5
source

This is a shot in the dark, because for code replication I will need to create a database, etc., but I believe that you want:

 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 is an array of a pair of expressions related to quantity and price . multiplyExpression - expression multiply:by: with parameters quantityPrice . ex is your expression sum: referring to a plural expression referring to the path of quantity and price.

I'm sure you will want to do something like this, but I cannot test it without creating a database like yours, etc., so this is just a theory.

0
source

Source: https://habr.com/ru/post/1392653/


All Articles