このトピックは興味深いです。そして、一見するとそれほど明確ではないかもしれません。以下にリストされているすべての情報源からの概要、要約として私の答えを理解してください。そして多分それはあなたに答えを与えるでしょう。
C# の観点からは、これらの動的プロパティを次のように考えることができます。
public virtual IDictionary<keyType, valueType> Additional { get; set; }
// (e.g. <string, object>
public virtual IDictionary Additional { get; set; }
これらは両方とも動的です。処理のためのコンパイル時のチェックはありませんIDictionary
。より良い状況は、一般的な引数が をチェックすることですIDictinary<,>
。しかし、動的マッピングについて話しているため、コンパイル時のチェックは犠牲にすることができます...
これらの辞書の 1 つにデータをロードするには、(ほとんどの場合) 異なるマッピングを行い、テーブルの構造を変える必要があります。Generic は、行に含まれるデータの転置に便利です。Non-Generic は列マッピングに使用できます(質問の例のように)。両方議論しましょう
1) 一般IDictionary<,>
- 動的行
よりタイプセーフなシナリオから始めましょう。次に、質問の近くに解決策をタッチします
1a) 三元協会
たとえば、役割/タイプに基づいて、いくつかの人物をエンティティ(契約など)にマッピングしてみましょう。1) マネージャー 2) リーダー 3) テスター。タイプ/役割ごとに 1 人しか存在しないことがわかっている場合 (テスターが 1 人だけ、または誰もいない)、次のように説明できます。
public virtual IDictionary<PersonType, Person> Persons { get; set; }
私たちは今、ダイナミックです。契約に関連する人物が 0 人、1 人、または 1 人以上存在する可能性があります。それぞれが によって一意である必要がありPersonType
ます。また、ランタイムに新しいPersonType
s を導入し、Contract の関連する Person セットを拡張することもできます...
マッピングは次のようになります
<map name="Persons" table="ContractPerson" >
<key column="ContractId"/>
<index-many-to-many column="PersonTypeId" class="PersonType"/>
<one-to-many class="Person"/>
</map>
これは6.9 の例です。三元関連。関係するエンティティは 3 つありますが、ランタイムにはまだ柔軟性があります。すでに述べたように、新しい PersonTypes を挿入して、これらの契約者関係を修正できます。
このシナリオは ( と比較してIDictiniary<string, object>
) 依然として多くのコンパイル時のチェックを提供します。
1b) 質問に近づく
上記のシナリオで、行<map>
の観点から使用して動的にしたい場合は、次のようなテーブルが必要です。
ElemntId| TheKey | TheValue (e.g. nvarchar)
1 | "name" | "Element A"
1 | "time" | "20:02"
1 | "date" | "2013-05-22"
1 | "value" | "11.22"
C# は次のようになります
public class Elements
{
...
public virtual IDictionary<string, string> Values { get; set; }
}
マッピング:
<map name="Values" table="DynamicElementValues" >
<key column="ElementId"/>
<index column="TheKey" type="string"/>
<element column="TheValue" type="string"/>
</map>
IDictionary<string, string>
すべての値が文字列であるためです。その値MetaData
を正しく解釈するには、いくつかが必要です
得られたもの:
負けた:
- 任意の値を SELECT または ORDER BY 句に入れる機能
- データ型を変換する必要があります(文字列から他のものに)
1c) キーとしてstring
実際、string
キーを持つ辞書は動的ですが、多すぎます。1a) に示されているように、 keyとして使用される値のセットを何らかの方法で管理することは常に良い考えです。これが、三項関連について説明した理由です。遅かれ早かれ、このディクショナリのデータを解釈する必要があるため、いくつかのメタデータを使用して、それらをキーとしても使用すると便利な場合があります...
2) 非汎用IDictionary
-動的列
今回は、実際に列の動的解法を試みます。
ここで使用できるNHibernateの機能は次のとおりです。
この種のマッピングは、質問、つまり私たちの要件に非常に近いものです。このC#表現があります
public class Elements
{
...
public virtual IDictionary DynamicValues { get; set; }
}
そして、これはマッピングになる可能性があります:
<join table="ElemntValues" >
<key column="ElementId" />
<dynamic-component name="DynamicValues" >
<property name="Time" type="TimeSpan" />
<property name="Date" type="DateTime" />
<property name="Salary" type="decimal" />
<property name="Color" type="string" />
<property name="WorkingDays" type="integer" />
<many-to one....
...
</dynamic-component>
</join>
この場合、(マッピングElementValues
の一部として) 親エンティティに結合された分離されたtable があります。<class>
マッピングはこれだけではありません。4.4など、他のマッピング タイプが存在する可能性があります。動的モデル
<class entity-name="DynamicValues"...
これらには、さらに特別な処理 (挿入、更新、削除) が必要になる場合があります。
結合は多くのことを簡素化しますが、常に SQL ステートメントで使用されます (親コア プロパティのみが必要な場合でも)
動的ですか?
さて、私たちは得ました:
- C# ではプロパティしかありません
IDictionary ElementValues
- NHibernate はランタイム チェックを行います。正しいタイプの値のみをキーに挿入できました (給与は 10 進数である必要があります)
- 一部の
MetaData
モデルでは、ユーザーに対して実際に動的にすることができます
- Mapped プロパティはいずれも SELECT (プロジェクション) および ORDER BY (ユーザーが気に入るはず) で使用できます。
負けた:
- すべてのデータ (例: session.Get<>(id)) がロードされるため、ある程度のパフォーマンスが得られます。
- 列を追加または削除する場合、動的ではありません。すべてのマッピングはアプリケーション配布の一部であり、実行時に変更することはできません。まあ、いつでも新しいマッピングだけを再デプロイできます...
2b) IDictionary とメタデータ
C#のIDictinary
観点からは非常に動的ですが (任意のキー/ペア値を含めることができます)、NHibernate マッピングにより、コンテンツは管理されます。としてマップされたプロパティに値のみinteger
を追加できました
integer
。しかし、実行時にどのように知るのでしょうか?どのようなキーを持っているのでしょうか? そこに配置してそこから取得できる値は何ですか? 繰り返しますが、メタデータが必要です...キーの役割を果たしませんが、実行時に重要になります。NHibernate のチェックは最後の防衛線です。
3) 実行時にマッピングを変更する方法 (新しい列が追加されました)?
さて、ドキュメントには何が記載されていますか?7.5. 動的コンポーネント:
この種のマッピングの利点は、マッピング ドキュメントを編集するだけで、展開時にコンポーネントの実際のプロパティを決定できることです。(DOM パーサーを使用して、マッピング ドキュメントを実行時に操作することもできます。)
...DOM パーサーを使用します。正直なところ、それが何を意味するのか、それをどのように実装するのかわかりません。
また、Mapping-by-Code の Adam Bar - 動的コンポーネントが記載されています (コメントを参照)
動的コンポーネントは、オブジェクト レベルとデータベース レベルの両方で実際に動的になることはできないと思います。コンポーネントパーツは通常の列として保存されるため、そのリストを知る必要があることに注意してください...
しかし、 Firo - NHibernate の動的マッピング (いくつかの抽出には複雑すぎるので見てください)からの素晴らしいアイデアがあります。本当に必要な場合、これは実際の動的な世界への解決策になる可能性があります...実行時の新しい列...での新しいキーマッピングIDictionary
概要
マッピングを使用すると、<map>
非常に動的になります。実行時の異なるキーと値。再デプロイする必要はありません。ただし、select または order by でこれらの動的プロパティを使用することはできません。これらの値でフィルタリングするのは難しい
を使用する<dynamic-component>
と、(そのままで) マッピングに依存します。ただし、列にデータがあるため、結合を使用してそれらを取得できます。フィルタリング、ソートが簡単。そして/しかし、metadata
私たちが持っているものとできることを私たちに導くものがあるに違いありません.
その他の情報源: