我有一个NSManagedObject
子类Foo
它有两个建模属性:a
和b
.
a
和b
是NSString
s,但不能保证它们会被实例化——它们也可能是 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 b
是 null
。但是当我将其更改为 a != nil
时效果很好(无论如何,这只是 b
的硬编码值!!)
编写了一些更多的测试代码来探讨这个问题,似乎在比较键时,如果 ==
的 LHS 或 RHS属性是 nil
,则结果数组为空。
另一方面,如果 LHS 和 RHS 均非 nil
,那么它似乎工作正常。
我在这里缺少什么?为什么 ==
比较两个键(其中一个或两个为 nil
)时,运算符失败?
最佳答案
nil
值在 SQLite 数据库中存储为 NULL
,并且 SQLite 将 NULL
视为
“未定义的值”。谓词“a != b”被转换为 SQLite 查询
SELECT ... FROM ZENTITY t0 WHERE t0.ZA <> t0.ZB
并且不会返回任何 t0.ZA
或 t0.ZB
为 NULL(也称为“未定义”)的行。
因此,a != b
不会返回任何 a
或 b
为 nil
的对象。
出于同样的原因,谓词 a == b
不会返回同时包含 a
的对象
和 b
为 nil
。
另一方面,谓词 a != nil
的翻译略有不同
SELECT ... FROM ZENTITY t0 WHERE t0.ZA IS NOT NULL
使用“IS NOT”代替“<>”。因此这个查询实际上返回所有对象
a != nil
(正如人们所期望的那样)。
我不知道核心数据文档中是否明确记录了此行为 (我还没有搜索过),但这就是 SQLite 处理 NULL 值的方式,它应该解释 您观察到的行为。
如果添加启动参数,您可以看到 SQLite 语句
-com.apple.CoreData.SQLDebug 3
用于方案编辑器中的可执行文件。
更新:来自"Attributes"在《核心数据编程指南》中:
You can specify that an attribute is optional—that is, it is not required to have a value. In general, however, you are discouraged from doing so—especially for numeric values (typically you can get better results using a mandatory attribute with a default value—in the model—of 0). The reason for this is that SQL has special comparison behavior for NULL that is unlike Objective-C's nil. NULL in a database is not the same as 0, and searches for 0 will not match columns with NULL.
这至少提到可选属性是特殊的并且可能不是 按预期行事。
"Predicate Programming Guide"还有一个关于 NULL 值和 NULL 测试的部分。
关于iphone - NSPredicate 比较可能为 nil 的键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17699511/