F#处理从数据库返回的空记录

时间:2014-01-14 23:35:05

标签: .net f# servicestack.redis

从数据库中检索唯一项时,我需要在客户端提供的ID没有数据时满足该方案。例如,ID不正确或缓存的数据已过期。

我在此示例中使用的特定数据库客户端库是ServiceStack.Redis,但我认为该原则适用于任何CLR库。

我使用下面显示的记录类型定义了我的数据结构。现在,当我使用客户端库检索数据库中不存在的密钥的数据时,将返回null值。这,我期待并很高兴。问题是F#编译器不允许我为这种情况进行模式匹配 - 即使它可以在运行时发生!

type MyRecordType = { id:int; name:string; desc:string }

let redis = new RedisClient("localhost")
let nullCheck =
    let item = redis.Get<MyRecordType> "xxx"
    // it is possible that item is null
    // but the compiler will not permit the match
    match item with
    | null -> None
    | _ -> Some item

Redis客户端库包含一个'ContainsKey'方法,返回一个我可以先使用的布尔值,但这里不需要两次调用数据库。另一种方法是使用在C#项目中定义的类作为数据结构,但这涉及太多的开销。该属性也不允许匹配null

我想知道我应该使用什么约定来处理这种情况,因为这似乎是一个非常常见的问题?

3 个答案:

答案 0 :(得分:4)

很遗憾,您无法在记录中使用AllowNullLiteral。因此,最好的解决方案是创建一个空值并进行相等的检查

if item = Operators.Unchecked.defaultof<_> then None else Some(item)

答案 1 :(得分:3)

我还发现this article使用了拳击。我认为它看起来更清晰:

if (box item = null) then None else Some item

答案 2 :(得分:3)

我认为这可能比我见过的其他选项好一点。 F#equals运算符非常强大,但是当你真正想知道的是否有一个空引用时,它也有点过分。

if obj.ReferenceEquals(item, null) then None else Some item

除非您正在进行批次比较,否则可能无关紧要,但确实存在差异:

> for i = 1 to 100000000 do bar = null |> ignore;;
Real: 00:00:00.233, CPU: 00:00:00.234, GC gen0: 0, gen1: 0, gen2: 0
val it : unit = ()
> for i = 1 to 100000000 do obj.ReferenceEquals(bar, null) |> ignore;;
Real: 00:00:00.030, CPU: 00:00:00.031, GC gen0: 0, gen1: 0, gen2: 0