2009-09-16 9 views
5

Próbuję pobrać kilka zapisów pewnego rodzaju, w oparciu o listę typów zdefiniowanych przez użytkownika ...Czy CoreData na iPhone obsługuje predykaty 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]; 

... Po uruchomieniu komunikat executeFetchRequest zgłasza wyjątek ...

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

Czy zrobiłem coś złego, czy to naprawdę nie jest obsługiwane?

+1

To powinno zadziałać, ale nie mogę do końca życia zrozumieć, dlaczego tak nie jest. Przeczytaj dokument Składnia ciągu formatowania predykatów i sprawdź, czy możesz znaleźć coś: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html – Tim

+0

Uzgodnione. Możesz spróbować NSArray zamiast NSSet, ale to powinno działać tak, jak zostało napisane. –

+2

Jeśli działa, powinieneś oznaczyć jedną z odpowiedzi jako poprawną. –

Odpowiedz

15

Wierzę, że Alex ma rację, że trzeba użyć NSArray, chociaż oczywiście byłoby ładniej, gdyby NSSet został tutaj zaakceptowany, ponieważ kolejność nie jest tak ważna (choć może to mieć wpływ na szybkość uruchamiania SQL) .

Na marginesie, nigdy nie używam + predicateWithFormat: wywoływać w jakimkolwiek kodzie, nigdy, ponieważ nie może on wykonywać kompilacji ani sprawdzać typów. Bardzo polecam korzystanie z poszczególnych klas.

W tym przypadku zrobiłbym:

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]; 

Nie dlatego, że byłoby to połów tego konkretnego błędu w czasie kompilacji, ale to byłby potencjalnie złapał go na poziomie NSExpression, dzięki czemu jest znacznie jaśniejsze co poszło nie tak.

+0

Działa za pomocą NSArray, a nie NSSet. Dziękuję wszystkim za złapanie tego. –

-1

Spróbuj zmienić swoje orzeczenie do @"ANY type IN %@"

0

Hmm. Próbowałem zarówno dodanie słowa kluczowego ANY i przy użyciu NSArray. Właściwie używałem NSAArray na początku, kiedy otrzymałem ten wyjątek od Core Data. Z perspektywy czasu myślę, że ponieważ łączyłem dwa wyrażenia z ORAZ był to problem dla danych podstawowych. (Wiem, że powinienem wrócić i to sprawdzić, ale ta myśl mi przyszło do głowy, podczas czytania tego postu). Tu jest mój oryginalny wyraz:

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

Moje rozwiązanie było podzielić go na dwie części. Teraz wydaje kwerendę dla BPM przy użyciu predykatu, ale biorę wynikową tablicę i używam -filteredArrayUsingPredicate z @ "genre IN% @". Tak więc:

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

To działa dla mnie.

0

Walczyłem z tym. W końcu doszedłem do wykonania predykatu podrzędnego dla każdego zestawu.

Tak na przykład:

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]; 

Zakładając tego typu jest NSSet. Jeśli nie, mógłbyś po prostu:

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