2014-01-14 72 views
1

當從數據庫中檢索唯一項目時,如果沒有客戶端提供的ID的數據,我需要滿足該方案。例如,ID不正確或緩存的數據已過期。F#處理從數據庫返回的空記錄

我在本例中使用的特定數據庫客戶端庫是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」方法返回一個boolean值,我可以使用第一,但兩次調用數據庫是不必要在這裏。另一種方法是使用C#項目中定義的類作爲數據結構,但這會涉及太多開銷。該屬性也不允許在null上進行匹配。

我想知道我應該用什麼約定來處理這種情況,因爲它看起來像是一個非常普遍的問題?

回答

3

不幸的是,您不能在記錄上使用AllowNullLiteral。因此,最好的辦法是隻創建一個空值,做一個平等的檢查,像這樣

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

你以前也玩過這個遊戲已經不是你! http://stackoverflow.com/a/9355926/1048369 – Nick

+0

@尼克 - 好點 - 我什至不記得那一個。 –

+0

我自己的答案也許對你感興趣...... – Nick

2

我還發現this article它利用拳。我認爲它看起來稍微更乾淨:

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

我認爲這可能比我見過的其他選項要好一些。 F#等號運算符非常強大,但當你真正想知道的是你是否有空引用時,它也有點矯枉過正。

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