NSFetchRequest с NSPredicate иногда выдает NSInvalidArgumentException - PullRequest
0 голосов
/ 27 мая 2011

Это меня сбивает с толку:

У меня есть основной набор данных, который я ищу / фильтрую, используя следующий код:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Lead" inManagedObjectContext:moc]];
NSString *predicateString = [NSString stringWithFormat:@"("
                       "(isLocalVersion == %@) AND (LeadStatusID =='Active')"
                       ") AND ("
                       "(LeadID contains[cd] '%@')"
                       "OR (AccountNumber contains[cd] '%@')"
                       "OR (ANY contactItems.FirstName contains[cd] '%@')"
                       "OR (ANY contactItems.LastName contains[cd] '%@')"
                       "OR (ANY addressItems.Address1 contains[cd] '%@')"
                       "OR (ANY addressItems.City contains[cd] '%@')"
                       ")", [NSNumber numberWithBool:YES], sTerm, sTerm, sTerm, sTerm, sTerm, sTerm];

NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
[fetchRequest setPredicate:predicate];

NSError *error = nil;
NSArray *leads = nil;
@try {
    leads = [moc executeFetchRequest:fetchRequest error:&error];
}
@catch (NSException *exception) {
    LogSevere(@"Error Executing Fetch Request: %@", exception);
    leads = [NSArray array];
}
@finally {
    [fetchRequest release];
}

sTerm - это просто NSString.

Это работает в 95% случаев, однако время от времени ловит NSInvalidArgumentException: Can't use in/contains operator with collection 10076173 (not a collection).

Формат строки предиката:

((isLocalVersion == 1) И (LeadStatusID == 'Актив')) И ((LeadID содержит [cd] 'i') ИЛИ (AccountNumber содержит [cd] 'i') ИЛИ (ЛЮБЫЕ контактные элементы.FirstName содержит [cd] 'i') ИЛИ (ЛЮБОЙ contactItems.LastName содержит [cd] 'i') ИЛИ (ЛЮБОЙ addressItems.Address1 содержит [cd] 'i') ИЛИ (ЛЮБОЙ addressItems.City содержит [cd] 'i'))

Мой улов позволяет мне не падать и просто возвращать 0 результатов, но это не оптимально. Кто-нибудь когда-нибудь видел это раньше?

Моя единственная подсказка в том, что , кажется, происходит после того, как я изменяю (и сохраняю) запись в основных данных (опять же только иногда).

Ответы [ 5 ]

2 голосов
/ 09 января 2014

Базовое хранилище SQL данных поддерживает только одну операцию «многие» на запрос;поэтому в любом предикате, отправленном в хранилище SQL, может быть только один оператор (и один экземпляр этого оператора) из ALL, ANY и IN.

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html

Может произойти следующее:

  • , если одно из ранних условий оценивается как TRUE, остальные условия не оцениваются, поэтому сбой не происходит
  • если вы доберетесь до OR (ANY contactItems.FirstName contains[cd] '%@') и это TRUE, вы получите первое использование ANY, не произойдет сбой
  • если вы доберетесь до OR (ANY contactItems.LastName contains[cd] '%@'), вы получите второе использование ANY, происходит сбой

Вам необходимо выполнить ЛЮБОЕ отдельно и объединить результаты, возможно, используя NSCompoundPredicate ;

2 голосов
/ 27 мая 2011

Да, вы не можете иметь выражения, которые оценивают коллекции как часть предиката fetchRequest. Это в документации :

Агрегатные выражения не поддерживаются Базовыми данными.

1 голос
/ 24 ноября 2012

Обнаружена похожая проблема с предикатом, который проверял долготу NSDecimalNumber, и его часть достигла longitude<-23 и вызвала obj_c_exception_throw без подробностей.Исправление должно было обеспечить пробел после <, то есть longitude < -23.В основном он рухнул для чего-либо с <- вместе, но не >-.

NSPredicate выдает некоторые странные недокументированные ошибки.

1 голос
/ 03 марта 2012

Является ли LeadID int свойством случайно?Я просто столкнулся с этой же проблемой, создавая предикат, в котором я проверяю, содержит ли одно или несколько свойств поисковый термин.Это работало в большинстве случаев времени, но время от времени происходило сбои с ошибками, как у вас.

Проблема заключалась в том, что все свойства, которые я проверял, были строками, кроме одного.Когда я удалил это свойство из предиката, все работало нормально.

Я подозреваю, 10076173 - это значение int LeadID для некоторого объекта в вашей базе данных.Похоже, что Core Data обычно преобразует int в строку, как вы ожидаете, но иногда это не так, и именно тогда происходит ошибка.Оператор CONTAINS не имеет смысла для целого числа, и он вылетает.


В качестве дополнительного доказательства я попытался изменить предикат для использования LIKE вместо СОДЕРЖИТ и я получил сообщение об ошибке, которое, наконец, сообщило мне о происходящем.Предикат был

itemNumber LIKE "* test *" OR модель LIKE "* test *" OR productDescription LIKE "* test *" [..snip ..]

и исключение было

'Невозможно выполнить сопоставление регулярных выражений для объекта 1008.'

В тот момент, когда я понял, 1008 выглядело знакомо ... как itemNumberэто Int32.


Что касается основных данных, то, как правило, но не всегда, при использовании оператора CONTAINS свойство int преобразуется в строку, я не знаю.Но я знаю, что предикат работал нормально, пока контекст не сохранил несохраненные изменения, в частности, когда было изменено свойство отношения объекта ко многим.

0 голосов
/ 27 мая 2011

Кажется, я помню, что у меня была похожая проблема с коллекциями в Core Data, где мой предикат fetch как-то приводил к неверному SQL (другие типы хранилищ данных работали нормально). Это не идеальное решение, но если у вас мало объектов, вы можете выполнить полную выборку, а затем отфильтровать результирующий набор по факту.

...