2017-04-14 68 views
1

當我保存一個新的F#記錄時,我在RavenDb文檔中獲得了一個名爲[email protected]的額外列,並且在代碼中加載或查看對象時顯示出來;它甚至通過我的F#API轉換爲JSON。在RavenDb中保存記錄並添加額外的Id列F#

這裏是我的F#記錄類型:

type Campaign = { mutable Id : string; name : string; description : string } 

我沒有做任何事情非常令人興奮的保存:

let save c : Campaign = 
    use session = store.OpenSession() 
    session.Store(c) 
    session.SaveChanges() 
    c 

保存記錄的新實例標識創建一個文檔的campaigns/289。下面是該文件的RavenDb的全部價值:

{ 
    "[email protected]": "campaigns/289", 
    "name": "Recreating Id bug", 
    "description": "Hello StackOverflow!" 
} 

現在,當我用C#這同一個數據庫(和文件),我沒有得到額外的[email protected]值。這是一個創紀錄的樣子,當我在C#中保存它:

{ 
    "Description": "Hello StackOverflow!", 
    "Name": "Look this worked fine", 
} 

(旁白 - 「名」與「名」是指我有2分名字列在我的文檔中我明白這個問題,至少)。

所以我的問題是:我如何擺脫額外[email protected]屬性當我保存在RavenDb的F#記錄?

+0

等一下,爲什麼那列是「額外的」?在「Campaign」記錄定義中,我可以清楚地看到它。 –

+0

由於C#對象定義也具有'Id'屬性,但它不顯示爲文檔值 - 它是用於訪問文檔的值。用F#創建的文檔既有用於查找特定數據庫記錄的Id,也有用於查找名爲'Id @'的文檔中的JSON值; C#版本在文檔中沒有「額外的」JSON值。 – Max

回答

3

這是一個......的組合,你不能稱它們爲「bug」,所以讓我們說F#編譯器和RavenDb中的「非直接特徵」。

F#編譯器爲Id記錄字段生成public後備字段。該字段被命名爲[email protected](所有F#支持字段的標準模式),並且它是public,因爲記錄字段是可變的。對於不可變的記錄字段,後備字段將爲internal。爲什麼它需要爲可變記錄字段生成公共後臺字段,我不知道。

現在,RavenDb在生成架構時,顯然會查看兩個屬性字段。這有點不標準。通常的做法是僅考慮屬性。但是,唉,Raven拿起名爲[email protected]的公共領域,並使其成爲架構的一部分。

您可以通過兩種方式解決這個問題:

首先,你可以使Id場不變。我不確定這是否適合您或RavenDb。也許不是,因爲Id可能是在插入時生成的。

,你可以聲明你的Campaign不是作爲F#記錄,但作爲一個真正的類:

type Campaign(id: int, name: string, description: string) = 
    member val Id = id with get, set 
    member val name = name 
    member val description = description 

這樣,所有支持領域內停留,沒有混亂就會出現。缺點是你必須編寫每個字段兩次:首先作爲構造函數參數,然後作爲類成員。

+1

從'Id'移除'mutable'會導致記錄無法從Raven加載Id,既可以保存新對象,甚至可以加載現有對象。我將研究類選項,但我也可以探索其他文檔數據庫,並查看是否更適合使用F#。感謝您的深入解釋,您真的幫助解釋了這個問題! – Max

+1

如果沒有'mutable',您可能會遇到此問題,其中Id未在保存時使用生成的值填充。如果你永遠不需要知道剛剛插入的記錄的標識,那就沒問題。 –

4

正如Fyodor所指出的,這是由F#在創建記錄類型時如何生成後臺字段引起的。RavenDB的默認合約解析器序列化該支持字段而不是公共屬性。

You can change the default contract resolver in ravendb.它會是這個樣子,如果你想使用Newtonsoft Json.Net:

DocumentStore.Conventions.JsonContractResolver <- new CamelCasePropertyNamesContractResolver() 

有爲什麼這個工程here的解釋(請參見標題爲:「解釋」)。簡而言之,Newtonsoft庫使用類型的公共屬性而不是私有後臺字段。

我還建議,而不必對Idmutable屬性,你可以把類型本身的[<CLIMutable>]屬性,如:

[<CLIMutable>] 
type Campaign = { Id : string; name : string; description : string } 

這使得它如此庫可以同時防止它發生變異值你的代碼。

相關問題