使用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。答案在这里没有适用。所以,我在这里添加我的研究结果,如果它们对其他人有用的话。
(根本问题不是特定于具有唯一约束。)
答案 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
。