2012-04-25 12 views
30

Torna anche bisogno di più aiuto con la costruzione di miei NSPredicates :(Combinando 'E' e 'O' Stato da NSPredicate

Category 
{ 
    name:string 
    subs<-->>SubCategory 
} 

SubCategory 
{ 
    name:string 
    numbervalue:NSNumber 
} 

Vorrei sapere come creare un predicato con E e OR .

per esempio, mi piacerebbe tornare ogni categoria con nome == "category_name", che ha anche una sottocategoria con un numbervalue di "valoreA" O "valoreB".

Ho provato ogni possibile combinazione di costruttori di predicati che potrei inventare, ma non riesco a farlo funzionare.

Questo è il mio miglior tentativo finora.

NSPredicate *predicate=[NSPredicate [email protected]"(name== %@) AND (ANY subs.numbervalue==%@ OR ANY subs.numbervalue==%@)", @"aname", value1, value2]; 

Modifica 1

Secondo tentativo. Il filtro sul 'numbervalue' non funziona ancora.

NSNumber valueA=[NSNumber numberWithInt:20]; 
NSNumber valueA=[NSNumber numberWithInt:90]; 
NSArray *arr=[NSArray arrayWithObject:valueA,valueB,nil]; 

predicate=[NSPredicate predicateWithFormat:@"(name==%@)AND(ANY subs.numbervalue IN %@)",@"aname",arr]; 

Edit 2

Ho provato filtraggio semplicemente numberValue e hanno lasciato il nome fuori alltogether.

1) utilizzando questo risultato viene restituito l'intero set anche se solo 1 elemento nel set ha il valore.

2) Utilizzando questo risultato lo stesso problema, ogni articolo nel set viene restituito anche se solo 1 di essi corrisponde.

Anche utilizzando la versione più semplice risulta lo stesso problema .... Non l'avevo notato prima.

NSPredicate *predicate=[NSPredicate [email protected]"(ANY subs.numbervalue==%@ ,valueA]; 

Quindi penso di aver ristretto il mio problema.

La categoria è un'entità. Sottocategoria è un'entità.

La categoria ha una relazione uno a molti con Sottocategoria ed è rappresentata come una NSSet di Sottocategoria.

Ogni sottocategoria ha un attributo denominato numbervalue.

Edit 3

Per provare Ho 2 Categorys. Entrambe le categorie hanno 10 sottotitoli, ciascuno con un valore nominale di 1 -10;

Utilizzando questo codice vengono restituite entrambe le categorie insieme a tutti e 10 i sottotitoli per ciascuno.

Il risultato atteso sono entrambe le categorie restituite, ciascuna con solo 2 sottotitoli.

Ho rintracciato tutti i miei oggetti e i dati sono corretti. Il problema è che non posso restituire una categoria che ha sottotitoli filtrati.

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSManagedObjectContext *context=[[DataSource sharedDataSource]managedObjectContext]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context]; 
[fetchRequest setEntity:entity]; 

[fetchRequest setFetchBatchSize:20]; 

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; 
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil]; 

NSPredicate *predicate; 
NSNumber *a=[NSNumber numberWithFloat:1]; 
NSNumber *b=[NSNumber numberWithFloat:2]; 
predicate=[NSPredicate predicateWithFormat:@"(SUBQUERY(subs,$x,$x.numbervalue==%@ or $x.numbervalue==%@)[email protected]> 0)",a,b]; 

[fetchRequest setPredicate:predicate]; 
[fetchRequest setSortDescriptors:sortDescriptors]; 

NSError *error = nil; 
[NSFetchedResultsContoller deleteCacheWithName:nil]; 

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:@"name" cacheName:@"Master"]; 
aFetchedResultsController.delegate = self; 

self.fetchedResultsController = aFetchedResultsController; 

if (![self.fetchedResultsController performFetch:&error]) { 

    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
} 
+0

Sono state prese delle 'NSCompoundPredicate'? Dovrebbe aiutarti. Prova anche a usare '... AND (QUALSIASI subs.numberValue IN% @)", @ "fooName", numArray' – Eimantas

+0

grazie per i suggerimenti – dubbeat

+0

utilizza $ x.numbervalue e non $ numbervalue. Quindi prova a impostare la cache su nil prima e vedi il risultato –

risposta

32

Farò quanto segue utilizzando un SUBQUERY.

[NSPredicate [email protected]"(name == %@) AND (SUBQUERY(subs, $x, $x.numbervalue == %@ or $x.numbervalue == %@)[email protected] > 0)", @"aname", value1, value2]; 

Provalo e fammi sapere.

Un'altra soluzione potrebbe essere quella di afferrare l'intera collezione subs e poi filtrata del recuperato impostato con un predicato per verificare se corrispondono elementi per value1 o value2.

Spero che aiuti.

Modifica

Se seguite Eimantas suggerimento fare per assicurarsi di creare il giusto matrice:

NSNumber valueA = [NSNumber numberWithInt:20]; 
NSNumber valueB = [NSNumber numberWithInt:90]; 
NSArray *arr = [NSArray arrayWithObjects:valueA, valueB, nil]; 
+0

quello che sembra accadere è se una collezione di sottotitoli ha un valore numerico di 90 per esempio ma il resto è dire 0, l'intera collezione di sottotitoli viene ancora restituita – dubbeat

+0

Prova ad usare solo * (SUBQUERY (subs, $ x, $ x.numbervalue ==% @ o $ x.numbervalue ==% @). @ count> 0) * nel predicato e il filtro della matrice con un predicato aggiuntivo per trovare quello nome. –

+0

Quale risultato si recupera utilizzando solo la SUBQUERY? –

49

Oltre alla risposta di @ Stuart, è possibile utilizzare NSCompoundPredicate per il proprio OR & E operazioni come questa.

Obj-C - O

// OR Condition // 

NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"]; 
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"]; 
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predicate1, predicate2]]; 

Obj-C - E

NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"]; 
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"]; 
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicate1, predicate2]]; 

Swift - O

let predicate1:NSPredicate = NSPredicate(format: "X == 1") 
let predicate2:NSPredicate = NSPredicate(format: "Y == 2") 
let predicate:NSPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate1,predicate2]) 

Swift - E

let predicate1:NSPredicate = NSPredicate(format: "X == 1") 
let predicate2:NSPredicate = NSPredicate(format: "Y == 2") 
let predicate:NSPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate1,predicate2]) 

Swift 3 - O

let predicate1 = NSPredicate(format: "X == 1") 
    let predicate2 = NSPredicate(format: "Y == 2") 
    let predicateCompound = NSCompoundPredicate.init(type: .or, subpredicates: [predicate1,predicate2]) 

Swift 3 - E

let predicate1 = NSPredicate(format: "X == 1") 
    let predicate2 = NSPredicate(format: "Y == 2") 
    let predicateCompound = NSCompoundPredicate.init(type: .and, subpredicates: [predicate1,predicate2]) 
+0

Lo adoro! Il mio codice sembra molto più bello del codice –

+0

Nice ... ha funzionato per me. Venerato !!! – NSPratik