2013-07-11 1 views
5

Si supponga di avere 2 entità, una Person e una Transaction.NSEpressione rispetto a una sottoquery NSPredicate

Person avere un rapporto a-molti con Transaction e Transaction entità ha amount e date. Il mio obiettivo era quello di avere un NSFetchRequest basato su Person, ma desidero solo conoscere le persone che hanno transazioni tra determinate date e lo SUM dell'importo delle transazioni.

mio codice è simile:

NSExpression *amountKeyPath = [NSExpression expressionForKeyPath:@"transactions.amount"]; 
NSExpression *sumAmountExpression = [NSExpression expressionForFunction:@"sum:" arguments:@[amountKeyPath]]; 

// Create the expression description for that expression. 
NSExpressionDescription *description = [[NSExpressionDescription alloc] init]; 
[description setName:@"sum"]; 
[description setExpression:sumAmountExpression]; 
[description setExpressionResultType:NSDecimalAttributeType]; 

// Create the sum amount fetch request, 
self.sumAmountFetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"]; 
self.sumAmountFetchRequest.resultType = NSDictionaryResultType; 
self.sumAmountFetchRequest.predicate = [NSPredicate predicateWithFormat:@"SUBQUERY(transactions, $t, $t.date >= %@ AND $t.date <= %@)[email protected] > 0", self.startDate, self.endDate]; 
self.sumAmountFetchRequest.propertiesToFetch = @[@"name", description]; 

Tutto sembra bene, ma ... Quando ho guardato la query SQL generato, sembra che:

SELECT t0.ZPERSONID, t0.ZNAME, 
    (SELECT TOTAL(t2.ZAMOUNT) FROM ZTRANSACTION t2 WHERE (t0.Z_PK = t2.ZPERSON)) 
FROM ZPERSON t0 
WHERE (SELECT COUNT(t1.Z_PK) FROM ZTRANSACTION t1 WHERE (t0.Z_PK = t1.ZPERSON AND ((t1.ZDATE >= ? AND t1.ZDATE <= ?)))) > ? 

Così, sembra che il NSExpression dichiarato, non rispetta lo NSPredicate della funzione fetchRequest creata.

Sarebbe possibile che l'espressione rispetti anche il predicato allegato a fetchRequest? O dal momento che NSExpression sta da solo, dovrei collegare un altro predicato ad esso?

+0

La dichiarazione SQLite sembra buono per me. Il predicato viene trasformato all'ultimo "WHERE" e ciò si applica all'intera frase. Ottieni il risultato atteso? –

+0

No, ho ricevuto la quantità di transazioni che appartengono a quella persona (non limitato al periodo di tempo - clausola WHERE) – Rpranata

+0

OK, ora capisco cosa intendi, e il mio commento sopra è sbagliato. –

risposta

5

Non ho nulla per sostenere la mia risposta, ma dopo aver lottato con questo per ore. Ho pensato che non fosse il fatto che il NSPredicate di non rispettasse il valore di fetchRequest, ma è più che il predicato di fetchRequest è una sottoquery.

SELECT t0.ZPERSONID, t0.ZNAME, 
    (SELECT TOTAL(t2.ZAMOUNT) FROM ZTRANSACTION t2 WHERE (t0.Z_PK = t2.ZPERSON)) 
FROM ZPERSON t0 
WHERE 
    (SELECT COUNT(t1.Z_PK) FROM ZTRANSACTION t1 WHERE (t0.Z_PK = t1.ZPERSON AND ((t1.ZDATE >= ? AND t1.ZDATE <= ?)))) > ? 

Così, la subquery nel predicato non è in realtà trasformato nella clausola WHERE che voglio. Penso che se fosse la creazione di un JOIN invece, funzionerebbe.

La mia soluzione, alla fine, è lavorare al contrario. Se creo il fetchRequest da Transaction, funziona perfettamente.

NSExpression *amountKeyPath = [NSExpression expressionForKeyPath:@"amount"]; 
NSExpression *sumAmountExpression = [NSExpression expressionForFunction:@"sum:" arguments:@[amountKeyPath]]; 

// Create the expression description for that expression. 
NSExpressionDescription *description = [[NSExpressionDescription alloc] init]; 
[description setName:@"sum"]; 
[description setExpression:sumAmountExpression]; 
[description setExpressionResultType:NSDecimalAttributeType]; 

// Create the sum amount fetch request, 
self.sumAmountFetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Transaction"]; 
self.sumAmountFetchRequest.resultType = NSDictionaryResultType; 
self.sumAmountFetchRequest.predicate = [NSPredicate predicateWithFormat:@"date >= %@ AND date <= %@", self.startDate, self.endDate]; 
self.sumAmountFetchRequest.propertiesToFetch = @[@"person.name", description]; 
self.sumAmountFetchRequest.propertiesToGroupBy = @[@"person.name"]; 

Che funziona perfettamente. Deve essere raggruppato dal "person.name" in modo che utilizzi lo sum: come desiderato.

L'SQL generato sarebbe

SELECT t1.ZPERSONID, total(t0.ZAMOUNT) 
FROM ZTRANSACTION t0 
     LEFT OUTER JOIN ZPERSON t1 ON t0.ZPERSON = t1.Z_PK 
WHERE (t0.ZDATE >= ? AND t0.ZDATE <= ?) GROUP BY t1.ZPERSONID 

Cheers,