Выполнение умножения (агрегации) с CoreData: как? - PullRequest
4 голосов
/ 24 января 2012

После фантастического урока Джеффа Ламарша я пытаюсь объединить данные для определенного подкласса 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 product

NAME         QUANTITY      PRICE
PRODUCT 1    2             23.00 
PRODUCT 2    4             12.00
PRODUCT 3    1             2.00

Метод aggregateOperation вернет 7, как и ожидалось.

Теперь у меня есть еще один шаг.Изменив этот метод, мне нужно вернуть общую стоимость заказа продукта.Другими словами, мне нужно рассчитать КОЛИЧЕСТВО * ЦЕНА для каждого продукта и, наконец, вернуть ИТОГО.

Не могли бы вы предложить мне правильный путь?Заранее спасибо.

РЕДАКТИРОВАТЬ Это новый код, который я использую после предложения 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 ]

5 голосов
/ 24 января 2012

Для тех, кто интересуется, я нашел решение проблемы выше.

Вот код:

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), где вы хотите выполнить извлечение данных.

Надеюсь, это поможет!

0 голосов
/ 24 января 2012

Это выстрел в темноте, потому что для репликации вашего кода мне нужно создать базу данных и т. Д., Но я считаю, что вы хотите:

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:, ссылающееся на множественное выражение, ссылающееся на пути количества и цены.

Я почти уверен, что вы захотите сделать что-то подобное, но я не могу проверить это без БД, настроенной как ваша, и т. Д., Так что это всего лишь теория.

...