ClassA
、ClassB
、ClassC
の3つのクラスがあるとします。ここで、クラスMessage
があるとします。 one-to-many
これら3つのクラスのそれぞれとメッセージの関係。
目標は、Message
がClassA
、ClassB
、またはClassC
オブジェクトのいずれかに「属している」必要があることです。 ClassA
/ClassB
/ClassC
オブジェクトは、0個または多数Messages
を持つことができます。 Messageクラスは3つのクラスのいずれでも同じです(つまり、3つのクラスA、B、Cのそれぞれに異なるクラスのメッセージがあってはなりません)。
次に、リレーショナルDBでのデータモデリングについて考えます(また、ORMを使用しています(この場合はEntity Framework Code First))。これらの3つのクラスのそれぞれと、Message
クラスをテーブルに追加します。
しかし、その後、問題は私が上で説明した関係を適用しようとしています。これにはいくつかの方法があります。
ClassAID
、ClassBID
、ClassCID
)を追加します。例えばメッセージがClassA
オブジェクトに属している場合、ClassAID
はそのオブジェクトのIDを値として持ち、ClassBID
とClassCID
はnullになります。これにより、Message
オブジェクトの値がこれらのFKの1つだけにあることを確認するために、制約/トリガーを作成する必要があります。また、メッセージがどのオブジェクトに属しているかを知りたいときはいつでも、ビジネスロジックレイヤーとプレゼンテーションレイヤーで少し醜くなります。MessageObjectには、ClassA、ClassB、およびClassCオブジェクトへのnull可能な参照があり、チェックする必要があります。 UIに表示する前に(メッセージからそのオブジェクトへのリンクなど)。ClassA
、ClassB
、ClassC
を一般化します。メッセージには、一般化クラスのIDのFKがあります。これにより複雑さが増し、メッセージがどのClassA/B/Cに関連付けられているかを簡単に判断するという問題は実際には解決されません。ClassToMessage
テーブル(リンクテーブルと同様)を追加します。前の2つを組み合わせたようなものですが、同じ理由でまだ正確な解決策ではありません。Entiy Frameworkアプローチを念頭に置いて、望ましいシナリオを達成するためのエレガントな方法があるかどうかを知りたいのですが。前もって感謝します。
EDIT 1:
Messageオブジェクトを、オブジェクトのツリーのような構造のコメント(またはファイル)として想像してください(ClassA
オブジェクトにはClassB
を含めることができ、ClassB
にはClassC
's ...を含めることができます)。これらすべてのクラスのオブジェクトに、0個または多くのコメントを付ける必要があります。すべてのコメントに同じコメントテーブルが必要です(コメントがClassA
またはClassB
...インスタンスに属しているかどうかは関係ありません)。また、特定のオブジェクトまたはコメントが属するオブジェクトのコメントを簡単に見つけられるようにする必要もあります。
編集2:
他の2つの選択肢:
StackOverflowでこの問題に対処しているのを見てきましたが、適切な解決策が見つからないようです。
編集3:
私は代替案#4(階層ごとのテーブル/クラステーブルの継承)を追求しており、これをより具体的なS.O.に進化させました。質問: Entity Framework 6 Code First-ツリー構造に関するコメント
ClassAとClassBが何を表すかが異なります本当に-一般的な名前は、適切な設計上の決定を行うのに役立ちません。たとえば、それらが共通の基本クラスでモデル化できる、またはモデル化すべきものであり、実際の「is-a」関係がある場合は、そのルートに進みます。
ClassAとClassBにこれらのメッセージ以外の共通点がない場合、継承はおそらく最善のアプローチではありません。この場合、ソリューション1と3の両方が可能です。どちらが適切かは、データベースがどの程度「防水」されているか、およびどのようなアクセスパターンとクエリが期待されるかによって異なります。
編集の最後のオプションを使用しますが、少し変更します。
これでは、具象クラスの変更を抽象化しました。
ただし、データベースでは、参照している具象クラスの種類とその具象クラスのIDを保存する列挙型の値を保存しています。この情報はファクトリーに渡すことができます。ファクトリーは、以前の列挙型とIDに基づく具体的なクラスのいずれかであるgenericClassを返すメソッドを提供する必要があります。
- Message
+ int Id
+ int TypeEnum
+ int ClassId
- Class
+ int Id
+ int TypeEnum
Class.TypeEnumは、Message.TypeEnumの "緩い"制約です。
これにより、ヌル値を許容する外部キーのために列を追加する必要を心配する必要がなくなります。
私が指摘したように、Message-classとClassA、ClassB、... ClassXの間のデータベース制約(外部キー)は使用できず、手動で処理する必要があることを考慮する必要があります。