带有 NSPredicate 的 NSFetchRequest 有时会抛出 NSInvalidArgumentException

Posted

技术标签:

【中文标题】带有 NSPredicate 的 NSFetchRequest 有时会抛出 NSInvalidArgumentException【英文标题】:NSFetchRequest with NSPredicate sometimes throws NSInvalidArgumentException 【发布时间】:2011-05-26 20:18:40 【问题描述】:

这个让我很困惑:

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

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) AND (LeadStatusID =='活动'))和 ((LeadID 包含 [cd] 'i')或 (帐号包含 [cd] 'i')或 (任何contactItems.FirstName 包含[cd] 'i')OR (ANY contactItems.LastName 包含[cd] 'i') 或(任何 addressItems.Address1 包含[cd] 'i')OR (ANY addressItems.City 包含[cd] 'i'))

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

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

【问题讨论】:

【参考方案1】:

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

Core Data 不支持聚合表达式。

【讨论】:

好的,那么在这种情况下,我应该得到isLocalVersionLeadStatusID 的结果集,然后单独评估每个剩余的表达式并组合结果? 谢谢。单独执行 OR 并组合结果似乎是有效的。 但我在这里看不到任何聚合表达式。你能指出哪些部分是聚合表达式吗?谢谢。【参考方案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;

【讨论】:

【参考方案3】:

LeadID 是否是 int 属性?我刚刚遇到了同样的问题,构建了一个谓词,我在其中检查一个或多个属性是否包含搜索词。它大部分时间都能正常工作,但时不时会出现像你一样的错误。

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

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


作为进一步的证据,我尝试将谓词更改为使用 LIKE 而不是 CONTAINS,我得到了一个相关的错误,最终让我知道正在发生的事情。谓词是

itemNumber LIKE "*test*" OR model LIKE "*test*" OR productDescription LIKE "*test*" [..snip..]

例外是

'无法对对象 1008 进行正则表达式匹配。'

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


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

【讨论】:

哇,非常有用的信息。我将不得不进一步调查。我使用了一个 cludge 来解决这个问题,但可能会用这个信息重新调查它。 +1【参考方案4】:

在检查 NSDecimalNumber 经度的谓词中发现了一个类似的问题,其中一部分到达 longitude<-23 并导致 obj_c_exception_throw 没有更多详细信息。修复是确保< 之后有一个空格,即longitude < -23。它基本上与<- 一起崩溃,但不是>-

NSPredicate 抛出一些奇怪的未记录错误。

【讨论】:

【参考方案5】:

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

【讨论】:

以上是关于带有 NSPredicate 的 NSFetchRequest 有时会抛出 NSInvalidArgumentException的主要内容,如果未能解决你的问题,请参考以下文章

带有 NSPredicate 的 NSFetchedResultsController 未更新

带有 groupBy 的 nspredicate 不喜欢带有 nsdate 的谓词比较

带有 NSPredicate 的 NSFetchRequest 不返回任何结果

带有特殊字符的 NSPredicate 过滤

带有 SUBQUERY 的 NSPredicate 不起作用

使用 NSPredicate 解析带有变量的公式