2017-04-14 4 views
1

新しいF#レコードを保存すると、RavenDbドキュメントに[email protected]という余分な列が表示され、コードをロードまたは表示すると表示されます。私のF#APIを通してJSONに変換さえさえしています。私はそれを保存することは非常にエキサイティングな何もしていないよF#で余分なID列を追加してRavenDbにレコードを保存

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

:ここ

は私のF#レコードタイプのレコードの新しいインスタンスを保存する

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

はIDを持つ文書を作成しますcampaigns/289です。ここでRavenDbにおける文書の完全な値は次のとおりです。私はC#で、この同じデータベース(およびドキュメント)を使用する場合

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

、私は余分な[email protected]値を取得できませんでした。これは、レコードは、私はC#で、それを保存したときのようになります。

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

(脇 - 「名前」対「名前」私は私の文書に2名の列を持っていることを意味し、私は、少なくとも、その問題を理解しています。)。

私の質問は:RavenDbにF#レコードを保存すると、[email protected]の余分なプロパティが作成されるのを避けるにはどうすればよいですか?

+0

待ち時間、その列が「余分な」理由は何ですか?あなたの 'Campaign'レコードの定義にはっきりと見ることができます。 –

+0

C#オブジェクト定義には 'Id'プロパティもありますが、ドキュメント値として表示されないため、ドキュメントにアクセスするための値です。 F#で作成されたドキュメントには、特定のデータベースレコードを検索するために使用されるIDと、Id @というドキュメントのJSON値の両方があります。 C#のバージョンには、ドキュメント内に「余分な」JSON値がありません。 – Max

答えて

3

これは、「バグ」とは言い難いので、F#コンパイラとRavenDbの両方で「非直接的な機能」と言いましょう。

F#コンパイラは、Idレコードフィールドのバッキングフィールドをpublic生成します。このフィールドの名前は[email protected](すべてのF#バッキングフィールドの標準パターン)です。レコードフィールドが変更可能であるため、publicです。不変レコードフィールドの場合、バッキングフィールドはinternalになります。なぜ私は可変レコードフィールドのためのパブリックバッキングフィールドを生成する必要があります、私は知らない。

ここで、RavenDbはスキーマを生成するとき、明らかにプロパティーフィールドの両方を調べます。これは少し非標準です。通常の方法はプロパティのみを考慮することです。しかし、ああ、Ravenは[email protected]という名前のパブリックフィールドを取得し、それをスキーマの一部にします。次の2つの方法でこの問題に対処することができます

まず、あなたは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 

この方法で、すべてのバックアップのフィールドが内部滞在し、混乱は生じないだろう。欠点は、すべてのフィールドを2回書く必要があります。最初はコンストラクタ引数として、次にクラスメンバとして使用します。

+1

'Id'から' mutable 'を削除すると、レコードは既存のものをロードするためにも新しいオブジェクトを保存するためにRavenからIdをロードできなくなります。私はクラスのオプションを調べますが、私は他のドキュメントDBを調べて、F#でよりうまくいくかどうかを調べることもできます。詳細な説明をいただきありがとうございます。本当に問題を説明してくれました! – Max

+1

'mutable'がなければ、Idがセーブ時に生成された値で設定されないこの問題に遭遇するかもしれません。ちょうど挿入されたレコードのIDを知る必要がなければ、あなたは大丈夫です。 –

4

Fyodorが指摘したように、これは、レコードタイプを作成するときにF#がバッキングフィールドを生成する方法によって発生します。RavenDBのデフォルトの契約リゾルバは、publicプロパティの代わりにそのバッキングフィールドをシリアル化します。あなたがNewtonsoft Json.Netを使用したい場合は

You can change the default contract resolver in ravendb.それは次のようになります。これはhereを働く理由の説明があり

DocumentStore.Conventions.JsonContractResolver <- new CamelCasePropertyNamesContractResolver() 

(:「説明」の項を参照してください)。簡単に言えば、Newtonsoftライブラリは、プライベートバッキングフィールドの代わりにそのタイプのパブリックプロパティを使用します。

私はまた、代わりにIdmutable性質を有するので、あなたのようなタイプ自体に[<CLIMutable>]属性を置くことができるお勧めします。

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

でそれを防止しながらライブラリは値を変異することができますので、これはそれを作りますあなたのコード。

関連する問題