FMDB:检索 Swift 中值类型的 NULL 值

FMDB: Retrieval of NULL values for value types in Swift

使用 FMDB,桥接用于 Swift,我检索了 SQLite 列定义的长整数值,如下所示

myColumn   BigInt NULL UNIQUE

使用 FMResultSet 的一行 Swift 代码(基于此处省略的直接 select 查询),如下所示

let value = resultSet.longForColumnName("myColumn")

这很好用。然而,当我检索并更新涉及该列的多条记录时,我 运行 违反了唯一键索引。事实证明,对于 NULL 值,上面那行 Swift 代码返回了 0 值,而且我找不到正确检测 NULL 值的快速方法。

在寻找处理此问题的正确方法时,我能找到的唯一相关问题是 。答案在这里不适用。所以,我在这里添加我的研究结果,它们是否对其他人有用。

(事实证明,根本问题并非特定于具有 Unique 约束。)

FMDB API,当从 Objective-C 版本桥接时,似乎没有直接的方法来检查 NULL 值(纠正我,如果我错了,请)。因此,对于定义为例如

的数据库列
myColumn   BigInt NULL

NULL 值将在涉及此列的任何 FMResultSet 中显示为值 0,代码为 Swift,如问题中所示。

(当顶部恰好有一个 UNIQUE 约束时,这将产生特别令人惊讶的结果。NULL 值将从数据库中检索为 0,以便在下一次保存操作时可能更新为这样,当涉及多个实体时违反了 Unique 约束,就像我的情况一样。但是,底层问题与约束无关。因此,我将重点关注一般的 NULL 值问题。)

为了避免这个问题,我们必须首先从相应的 FMResultSet 中检索列的值作为对象,如下所示:

let objectValue = resultSet.objectForColumn("myColumn")

如果objectValue恰好是type/valueNSNull(),那么我们就有了一个NULL值,可以进行相应的处理。否则,我们可以使用正常的 longForColumnName 方法。 (然而,对于字符串等对象类型,FMDB 实现自然 returns 一个可选的,对于 NULL 的数据库值将是 nil!)

为了使这更容易,我使用了 FMResultSet class 的扩展(我更喜欢按索引检索),如下所示:

extension FMResultSet {
    func isNullForColumnIndex(columnIdx: Int32) -> Bool {
        let value = self.objectForColumnIndex(columnIdx)
        if let nullValue = value as? NSNull {
            return true
        } else {
            return (value == nil)
        }
    }
}

假设 "myColumn" 会出现在结果集中的索引 0 处,这会将上面示例中的数字类型的值提取减少到这样的一行:

let num: Int64? = (result.isNullForColumnIndex(0) ? nil : Int64(result.longForColumnIndex(0)))

当然,我也可以添加一个方法,例如 optionalLongForColumnIndex(columnIndex: Int32) -> Int64?,它包括 NULL 检查和值检索。对于每个值类型,这只需要一个这样的方法,到目前为止我已经避免了。

Marco,您自己的回答非常好:它准确描述了正在发生的事情。然而,在 Swift 中编码时,有 ccgus/fmdb 类型更安全的替代方案。您可以尝试 https://github.com/stephencelis/SQLite.swift (pretty popular) or https://github.com/groue/GRDB.swift(在精神上更接近 fmdb)。

我在 Objective-C 使用 FMDB 时遇到了类似的问题。 使用 longForColumnIndex.

时也会得到 0 而不是 nil

但是使用: NSNumber* object = [resultSet objectForColumnIndex:0]; 按预期工作。

如果存储了值,则给出完全有效的 NSNumber 对象,否则 NSNull