4

a fantastic tutorial by Jeff Lamarcheに続いて、NSManagedObjectという特定のサブクラスのデータを集計しようとしています。CoreDataで乗算(集計)を実行するにはどうすればよいですか?

これはシナリオです。 NSManagedObjectクラスを拡張するProductという名前のクラスを作成しました。 Productクラスは、次のような3つのプロパティました:

@property (nonatomic, retain) NSString* name; 
@property (nonatomic, retain) NSNumber* quantity; 
@property (nonatomic, retain) NSNumber* price; 

また、私は和集約を行うProduct+Aggregateというカテゴリを作成しました。特に、Jeffのチュートリアルに続いて、私はquantity属性の合計を管理しました。

+(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を返すと言います。

もう1歩進んでいます。その方法を変更すると、私は製品注文の総コストを返す必要があります。つまり、商品ごとにQUANTITY * PRICEの値を計算し、最後にTOTALを返す必要があります。

私に正しい方法を教えてください。前もって感謝します。

EDITこれはCyber​​foxの提案後に使用する新しいコードですが、残念ながらうまくいきません。

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 

答えて

5

興味がある方は、私は上記の問題の解決策を見つけました。

ここでは、コードです:

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.は、を使用すると、NSNumberを返し、データ取得を実行する2つの属性(NSString)とパラメータとして管理コンテキストを受け取るClassメソッドを作成します。

希望すると助かります!

0

あなたのコードを複製するので、これは私がなど、データベースを構築する必要があるだろう、暗闇の中でショットですが、私はあなたがしたいことを信じる:

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は配列でありますquantitypriceを参照してください。 multiplyExpressionは、quantityPriceのパラメータを持つ式multiply:by:です。 exは、数量と価格のキーパスを参照する複数式を参照するsum:式です。

私はあなたのようなことをしたいと思っていますが、あなたのようなDBを設定しないとテストできません。

+0

ご回答いただきありがとうございます。それを実行すると、コードはNSArray * results = [context executeFetchRequest:request error:nil];で終了します。例外は次のとおりです。** EXCEPTIONS:フレームから巻き戻す**任意の提案ですか? –

+0

編集したバージョンを取得しましたか? ':'を 'multiply:by:'式に追加しましたか? StackOverflowは私に約10分間それを修正する手間を与えていました。 :( スタックトレースのどこかに、より包括的なエラーがあるはずです。「キャッチされていない例外によるアプリケーションの終了」NSInternalInconsistencyException、理由: '更新中にエラーが発生しました。 – Cyberfox

+0

はい、スタックトレースはその例外を表示します。完全なスタックトレースを表示するために何かできますか?スキームプロジェクトで例外ログが有効になっています。 –

関連する問題