带有NSPredicate的NSFetchRequest有时会抛出NSInvalidArgumentException

时间:2011-05-26 20:18:40

标签: objective-c core-data nspredicate nsfetchrequest

这个令我感到困惑:

我有一个核心数据集,我使用以下代码搜索/过滤:

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).

Predicate String格式为:

  

((isLocalVersion == 1)AND   (LeadStatusID =='有效'))和   ((LeadID包含[cd]'i')或   (AccountNumber包含[cd]'i')或   (任何contactItems.FirstName   包含[cd]'i')或(任何   contactItems.LastName包含[cd]   'i')OR(任何addressItems.Address1   包含[cd]'i')或(任何   addressItems.City包含[cd]'i'))

我的捕获允许我不崩溃并且只返回0结果,但这不是最佳的。有没有人见过这个?

我唯一的线索是,在我修改(并保存)核心数据中的记录后,似乎会发生(有时只会)。

5 个答案:

答案 0 :(得分:2)

是的,您不能将表达式作为fetchRequest的谓词的一部分来计算集合。 This is in the documentation

  

Core Data不支持聚合表达式。

答案 1 :(得分:2)

  

Core Data SQL存储每个查询仅支持一对多操作;因此,在发送到SQL存储的任何谓词中,ALLANYIN可能只有一个运算符(以及该运算符的一个实例)。

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崩溃

您需要单独执行ANY并合并结果,可能使用NSCompoundPredicate;

答案 2 :(得分:1)

LeadID 是一个int属性吗?我刚遇到同样的问题,构建一个谓词,我检查一个或多个属性是否包含搜索词。它当时大多数,但是它偶尔会因为你的错误而失败。

问题是我检查的所有属性都是字符串,除了一个。当我从谓词中删除该属性时,一切正常。

我怀疑 10076173 是数据库中某个对象的LeadID的int值。似乎Core Data将通常将int转换为字符串,就像您期望的那样,但有时它不会,并且当错误发生时。 CONTAINS 运算符对整数没有意义,它会崩溃。


作为进一步的证据,我尝试更改谓词以使用 LIKE 而不是 CONTAINS ,我收到了一个相关的错误,最终让我知道发生了什么。谓词是

  

itemNumber LIKE“* test *”或模型LIKE“* test *”或productDescription LIKE“* test *”[..snip ..]

,例外是

  

'不能在对象1008上进行正则表达式匹配。'

此时我意识到1008看起来很熟悉......就像itemNumber,这是一个Int32。


至于Core Data通常(但并非总是)在使用CONTAINS运算符时将int属性转换为字符串的原因,我不知道。但我确实知道谓词工作正常,直到上下文有未保存的更改:特别是当对象的to-many关系属性发生更改时。

答案 3 :(得分:1)

发现一个类似的问题,谓词正在检查NSDecimalNumber经度,部分内容来到longitude<-23并导致obj_c_exception_throw没有更多细节。修复是为了确保在<之后有一个空格,即longitude < -23。它基本上与<- >-一起崩溃,但不是{{1}}。

NSPredicate会抛出一些奇怪的无证错误。

答案 4 :(得分:0)

我似乎记得Core Data中的集合存在类似问题,其中我的fetch谓词以某种方式导致无效的SQL(其他数据存储类型工作正常)。它不是一个理想的解决方案,但是如果你有足够的对象,你可以完成一次完整的提取,然后在事后过滤结果集。