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

时间:2015-10-23 15:46:21

标签: swift fmdb

使用FMDB,桥接在Swift中使用,我检索了像这样的SQLite列定义的长整数值

myColumn   BigInt NULL UNIQUE

使用一行FMResultSet的Swift代码(基于这里遗漏的简单选择查询),像这样

let value = resultSet.longForColumnName("myColumn")

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

在搜索处理此问题的正确方法时,我能找到的唯一相关问题是this one concerning empty strings being returned for text columns with Null values。答案在这里没有适用。所以,我在这里添加我的研究结果,如果它们对其他人有用的话。

(根本问题不是特定于具有唯一约束。)

3 个答案:

答案 0 :(得分:3)

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

的数据库列
myColumn   BigInt NULL

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

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

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

let objectValue = resultSet.objectForColumn("myColumn")

如果objectValue恰好是类型/值NSNull(),那么我们有一个NULL值并且可以相应地处理它。否则,我们可以使用普通的longForColumnName方法。 (但是对于诸如字符串之类的对象类型,FMDB实现自然会返回一个可选项,对于NULL的数据库值将为nil!)

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

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检查和值检索。对于每种值类型,这只需要一种这样的方法,到目前为止我已经避免了这种方法。

答案 1 :(得分:1)

Marco,你自己的答案很棒:它描述了到底发生了什么。然而,当在Swift中编码时,ccgus / fmdb还有类型更安全的替代品。您可以尝试https://github.com/stephencelis/SQLite.swift(非常受欢迎)或https://github.com/groue/GRDB.swift(更接近精神中的fmdb)。

答案 2 :(得分:0)

我在FMDB的Objective-C中遇到了类似的问题。 使用0时也会得到nil而不是longForColumnIndex

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

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