布尔谓词导致零行数

Posted

技术标签:

【中文标题】布尔谓词导致零行数【英文标题】:Bool predicate causes zero rows count 【发布时间】:2019-04-21 20:18:22 【问题描述】:

当我尝试执行 CoreData 获取请求时,我得到了正确的行数。

let req = Track.fetchRequest()
return try context.count(for: req)

// result: 81

有效:

当我尝试添加布尔条件时,

let req = Track.fetchRequest()
req.predicate = NSPredicate(format: "isSentToServer = NO")
return try context.count(for: req)

// result: 0

它没有。结果总是0(但它仍然应该是81)无论我尝试什么:

NSPredicate(format: "isSentToServer = %i", NSNumber(value: false))
NSPredicate(format: "isSentToServer = %@", NSNumber(value: false))
NSPredicate(format: "isSentToServer = 0")
NSPredicate(format: "isSentToServer = %@", false)
NSPredicate(format: "isSentToServer = %@", 0)
NSPredicate(format: "isSentToServer != YES")
NSPredicate(format: "isSentToServer == NO")
NSPredicate(format: "isSentToServer == %@", "NO")

注意:isSentToServer 是正确识别的属性,更改大小写或添加 Z 将无济于事。

是否有许多 Swift 教程作者不知道的变化?

编辑:Track 类由 Core Model 实体编辑器自动生成,isSentToServer 数据类型为Bool(编辑器中的“布尔”)(不是Bool?

更新

这是我的测试代码的输出,建议使用-com.apple.CoreData.SQLDebug 1(谓词:isSentToServer != YES):

CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA'
CoreData: sql: pragma recursive_triggers=1
CoreData: sql: pragma journal_mode=wal
CoreData: sql: SELECT Z_VERSION, Z_UUID, Z_PLIST FROM Z_METADATA
CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA'
CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_MODELCACHE'
CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'ACHANGE'
CoreData: sql: SELECT COUNT(*) FROM ZTRACK
CoreData: annotation: total count request execution time: 0.0004s for count of 90.
Total track objects: 90
CoreData: sql: SELECT COUNT( DISTINCT t0.Z_PK) FROM ZTRACK t0 WHERE  t0.ZISSENTTOSERVER <> ? 
CoreData: annotation: total count request execution time: 0.0005s for count of 0.
Track objects pending upload: 0

对于 = NO 和其他“相等”的情况,它会生成 SQL "= ?"

如何创建Track 对象?

let track = Track(context: context) // context is from AppDelegate, auto-generated by Xcode
// set up some properties
// not assigning any isSentToServer value explicitly
context.save() // no errors

编辑 2:注意,我已经在我的 Xcode 中尝试过 iPhone 6 模拟器的“擦除数据”,并重新创建了我的 Track 对象,但第二个请求仍然返回零行数。

Xcode:版本 10.2 (10E125)

针对 ios SDK/版本:11.0 或 12.2,没有区别

$ xcodebuild -showsdks
iOS SDKs:
    iOS 12.2                        -sdk iphoneos12.2

iOS Simulator SDKs:
    Simulator - iOS 12.2            -sdk iphonesimulator12.2

【问题讨论】:

谓词编程指南指出,对于布尔值,您应该使用类似"someAttribute == YES" 的东西。我在您的列表中没有看到的一件事是"isSentToServer == NO"。试试看。 "isSentToServer = NO" 应该适用于布尔属性(=== 在谓词中被同等对待)。 为了完整起见,更新您的问题,显示实体声明,清楚地显示isSentToServer 属性是如何声明的。 我在模拟器中的 iOS 应用程序显示第二个请求的结果 0,我敢肯定。我试图交换请求的顺序(有和没有谓词),但这没有区别。我从viewWillAppear() 提出这些请求,并通过print() 进行报告。我使用相同的上下文,但每次调用都使用新的 FetchRequest。 激活核心数据调试(启动参数-com.apple.CoreData.SQLDebug 3,参见developer.apple.com/library/archive/documentation/Cocoa/…)并检查输出。 【参考方案1】:

这是一个带有解决方法的评论。

有帮助的是以下组合:

    对象显式设置track.isSentToServer = false对象明确设置track.time = Date()(我不在谓词中使用此字段)(生成类型为:Date?

因此,谓词有效。

虽然,我的期望很符合逻辑:

    false 必须是默认值,因为它具有 Bool 类型(不是 Bool?)。 nil 必须是 Date? 属性的默认值,并且不得影响未提及它的谓词。

我无法找到有关此行为是否记录在案的信息。

【讨论】:

根据我的经验,布尔属性可以具有三个值:true、false 和 null。提取谓词和过滤谓词以不同方式处理空值。解决方案:始终为数据模型中的布尔属性设置默认值。 请问有什么经验?我看到你在苹果上的代码,我只是从来没有见过布尔值有三个可能的值,尤其是在 SQL 中。仅适用于特定框架中的可空值,例如 Swift 或 C# 中的 bool?,但我在自动生成的实体类中有 bool。在 SQL/SQLite 中,bool 字段是 tinyint 或 integer,0 被认为是 false,而不是 null AFAIK? 可选布尔属性的值可以是nil。数据模型中的默认默认值为 None。

以上是关于布尔谓词导致零行数的主要内容,如果未能解决你的问题,请参考以下文章

具有分配律的 Java 谓词

存储在 hashMap 中的结果集给出零行数

Prolog 中的复合布尔表达式

布尔注释导致重复?

boost::polygon 布尔减法导致额外的行

为啥这个 stl 函数调用会导致不正确的布尔评估? [复制]