2

我有一个NSManagedObject子类Foo,它有两个建模属性:ab.

abNSStrings,但不能保证它们会被实例化——它们也可以是nil。事实上,就像现在发生的那样,所有Foo实例都b等于nil

我想获取所有Foo对象,例如a != b

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Foo"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"a != b"];    
NSArray *result = [managedObjectContext executeFetchRequest:fetchRequest error:nil];

结果数组是空的,即使我知道有 10 个a绝对不是 nil的对象。

事实上,我什至可以通过将谓词调整为:

fetchRequest.predicate = [NSPredicate predicateWithFormat:@"a != nil"];

效果很好,并返回给我 10 个对象。

NSPredicate/的这种行为NSFetchRequest很奇怪,我不明白为什么它会为原始a != b谓词 where bis返回一个空结果null。但是当我将其更改为时工作正常a != nil(这只是硬编码的值b!!)

编写了更多测试代码来探索这个问题,似乎在比较键时,如果==属性的 LHS 或 RHS 是nil,则结果数组为空。

另一方面,如果 LHS 和 RHS 都不是nil,那么它似乎工作正常。

我在这里想念什么?为什么==操作员在比较两个键中的一个或两个时会失败nil

4

1 回答 1

2

nil值存储NULL在 SQLite 数据库中,并且 SQLite 将NULL其视为“未定义值”。谓词“a != b”被翻译成 SQLite 查询

SELECT ... FROM ZENTITY t0 WHERE  t0.ZA <> t0.ZB

并且不会返回任何t0.ZAt0.ZB为 NULL 的行(也称为“未定义”)。因此,a != b不返回ab为 的任何对象nil

出于同样的原因,谓词a == b不会返回同时存在ab的对象nil

另一方面,谓词a != nil的翻译略有不同

SELECT ... FROM ZENTITY t0 WHERE   t0.ZA IS NOT NULL

使用“不是”而不是“<>”。因此,这个查询确实返回了所有对象 a != nil(正如人们所期望的那样)。

我不知道核心数据文档中是否明确记录了这种行为(我还没有搜索过),但这是 SQLite 处理 NULL 值的方式,它应该解释你观察到的行为。

如果添加启动参数,您可以看到 SQLite 语句

-com.apple.CoreData.SQLDebug 3

对于方案编辑器中的可执行文件。

更新:来自“核心数据编程指南”中的“属性”:

您可以指定一个属性是可选的——也就是说,它不需要有一个值。但是,通常不鼓励您这样做,尤其是对于数值(通常,您可以使用具有默认值(在模型中)为 0 的强制属性获得更好的结果)。原因是 SQL 对 NULL 有特殊的比较行为,这与 Objective-C 的 nil 不同。数据库中的 NULL 与 0 不同,搜索 0 将不会匹配具有 NULL 的列。

这至少确实提到了可选属性是特殊的,并且可能不会按预期运行。

谓词编程指南”还有一个关于 NULL 值和 NULL 测试的部分。

于 2013-07-17T12:54:30.660 回答