2009-09-16 3 views
5

Sto cercando di prendere un gruppo di record di un certo tipo, sulla base di un elenco di tipi definiti dall'utente ...CoreData su iPhone supporta i predicati IN?

[fetchRequest setEntity:[NSEntityDescription entityForName:@"myRecord" inManagedObjectContext:self.managedObjectContext]]; 
NSSet *shipTypes = [NSSet setWithObjects:[NSNumber numberWithInt:70], 
        [NSNumber numberWithInt:71], 
        [NSNumber numberWithInt:72], 
        [NSNumber numberWithInt:73], 
        [NSNumber numberWithInt:74], 
        nil]; 
NSPredicate *aPredicate = [NSPredicate predicateWithFormat:@"type in %@", shipTypes]; 
[fetchRequest setPredicate:aPredicate]; 
theRecords = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 

... quando viene eseguito, il messaggio executeFetchRequest genera un'eccezione ...

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'unimplemented SQL generation for predicate : (type IN {71, 73, 70, 72, 74})' 

Ho fatto qualcosa di sbagliato, o questo non è davvero supportato?

+1

che dovrebbe funzionare, ma non posso per la vita di me capire perché non lo è. Leggere il predicato Formato document String Sintassi e vedere se è possibile trovare qualsiasi cosa: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html – Tim

+0

Concordato. Potresti provare un NSArray invece di un NSSet, ma dovrebbe funzionare come scritto. –

+2

Se hai funzionato dovresti contrassegnare una delle risposte come corretta. –

risposta

15

Credo che Alex abbia ragione che devi usare un NSArray, anche se ovviamente sarebbe più bello se NSSet venisse accettato qui, dato che l'ordine non è così importante (anche se potrebbe in teoria influire sulla velocità con cui SQL può essere eseguito) .

Come nota a margine, non uso mai + predicateWithFormat: chiama in qualsiasi codice, mai, perché non è in grado di eseguire la sanità in fase di compilazione o il controllo dei tipi. Consiglio vivamente di utilizzare le singole classi.

In questo caso, mi piacerebbe fare:

fetchRequest.entity = [NSEntityDescription entityForName:@"myRecord" inManagedObjectContext:self.managedObjectContext]]; 

NSArray *shipTypes = [NSArray arrayWithObjects:[NSNumber numberWithInt:70], 
             [NSNumber numberWithInt:71], 
             [NSNumber numberWithInt:72], 
             [NSNumber numberWithInt:73], 
             [NSNumber numberWithInt:74], 
             nil]; 
fetchRequest.predicate = [NSComparisonPredicate predicateWithLeftExpression:[NSExpression expressionForKeyPath:@"type"] rightExpression:[NSExpression expressionForConstantValue:shipTypes] modifier:NSDirectPredicateModifier type:NSInPredicateOperatorType options:0]; 

theRecords = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 

Non che questo avrebbe preso questo errore particolare in fase di compilazione, ma sarebbe potenzialmente catturato al livello NSExpression, rendendo così molto più chiaro che cosa è andato storto.

+0

Funziona usando NSArray, piuttosto che NSSet. Grazie a tutti per aver capito questo. –

-1

provare a modificare le predicato @"ANY type IN %@"

0

Hmm. Ho provato ad aggiungere la parola chiave ANY e ad usare NSArray. In realtà stavo usando NSAArray per iniziare quando ho ricevuto questa eccezione da Core Data. In retrospettiva, penso che poiché stavo combinando due espressioni con AND era un problema per i dati di base. (So ​​che dovrei tornare indietro e verificare questo, ma questo pensiero appena venuto in mente, durante la lettura di questo post.) Ecco la mia espressione originale:

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"BPM BETWEEN { %d, %d } AND GENRE IN %@", lower, upper, genres]; 

La mia soluzione era quella di suddividerla in due parti. Ora, invio la query per BPM utilizzando il predicato, ma prendo la matrice risultante e uso -filteredArrayUsingPredicate con @ "genere IN% @". Quindi:

array = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"genre IN %@", genres]]; 

Questo funziona per me.

0

ho lottato con questo. Alla fine ho finito per fare un predicato secondario per ciascuno dei set.

Così, per esempio:

NSMutableArray *subpredicates = [NSMutableArray array]; 

NSArray *shipTypes = [NSArray arrayWithObjects:[NSNumber numberWithInt:70], 
            [NSNumber numberWithInt:71], 
            [NSNumber numberWithInt:72], 
            [NSNumber numberWithInt:73], 
            [NSNumber numberWithInt:74], 
            nil]; 

for (NSNumber *num in shipTypes) { 
    [subpredicates addObject:[NSPredicate predicateWithFormat:@"ANY type == %@", num]];   
} 

NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates]; 

Questo supponendo che tipo è un NSSet. Se non è si può solo avere:

for (NSNumber *num in shipTypes) { 
    [subpredicates addObject:[NSPredicate predicateWithFormat:@"type == %@", num]];   
}