Выполнение умножения (агрегации) с CoreData: как?
Следуя фантастическому учебнику Джеффа Ламарша, я пытаюсь объединить данные для определенного подкласса NSManagedObject
,
Это сценарий. Я создал класс с именем Product
это расширяет NSManagedObject
учебный класс. Product
Класс имеет три свойства, такие как следующее:
@property (nonatomic, retain) NSString* name;
@property (nonatomic, retain) NSNumber* quantity;
@property (nonatomic, retain) NSNumber* price;
Я также создал категорию под названием Product+Aggregate
где я выполняю агрегацию суммы. В частности, следуя обучающей программе Джеффа, я управлял суммой атрибута количества.
+(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 для каждого продукта и, наконец, вернуть ИТОГО.
Не могли бы вы предложить мне правильный путь? Заранее спасибо.
РЕДАКТИРОВАТЬ Это новый код, который я использую после предложения Cyberfox, но, к сожалению, он не работает.
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
2 ответа
Для интересующихся я нашел решение проблемы выше.
Вот код:
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];
PS, чтобы использовать его, создайте метод класса, который возвращает NSNumber
и принимает в качестве параметров управляемый контекст и 2 атрибута (NSString
) где вы хотите выполнить поиск данных.
Надеюсь, поможет!
Это выстрел в темноте, потому что для репликации вашего кода мне нужно создать базу данных и т. Д., Но я считаю, что вы хотите:
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
массив пар выражений, относящихся к quantity
а также price
,multiplyExpression
это выражение multiply:by:
с параметрами quantityPrice
,ex
твой sum:
выражение, ссылающееся на множественное выражение, ссылающееся на количественные и ценовые ключевые пути.
Я почти уверен, что вы захотите сделать что-то подобное, но я не могу проверить это без БД, настроенной как ваша, и т. Д., Так что это всего лишь теория.