1つのテーブルに、他の複数のテーブルの子になることができるレコードが含まれているデータベースがあります。所有者のIDとテーブル名で構成される「ソフト」外部キーがあります。この(アンチ)パターンは、「多形関連」として知られています。これまでで最高のデータベース設計ではないことは承知しており、近いうちに変更する予定ですが、近い将来には変更しません。簡単な例を示しましょう。
、、およびの両方Event
にコメントのレコードがあります。ご覧のとおり、FKの厳しい制約はありません。Person
Product
Entity Frameworkでは、サブレーザーなどでこのモデルをサポートし、コレクションなどを作成することComment
ができますEventComment
。Event
EventComments
サブクラスと関連付けは、データベースから基本モデルを生成した後に手動で追加されます。OwnerCode
このTPHモデルの識別子です。、、、およびは完全に異なるエンティティであることEvent
に注意してください。それらに共通の基本クラスを設定することは意味がありません。Person
Product
これはデータベースファーストです。私たちの実際のモデルはこのように機能しますが、問題ありません。
わかった。次に、コードファーストに移行します。そこで、データベースをコードファーストモデル(EF Power Tools)にリバースエンジニアリングし、サブクラスを作成し、関連付けと継承をマッピングしました。Linqpadでモデルに接続しようとしました。トラブルが始まったのはその時です。
このモデルでクエリを実行しようとすると、InvalidOperationExeception
外部キーコンポーネント'OwnerId'は、タイプ'EventComment'で宣言されたプロパティではありません。モデルから明示的に除外されていないこと、および有効なプリミティブプロパティであることを確認してください。
これは、双方向の関連付けがありOwnerId
、のプロパティとしてマップされている場合に発生しComment
ます。EventMap
私のクラス( )のマッピングはEntityTypeConfiguration<Event>
次のようになります。
this.HasMany(x => x.Comments).WithRequired(c => c.Event)
.HasForeignKey(c => c.OwnerId);
OwnerId
そこで、モデルを使用せずに関連付けをマッピングしようとしました。
this.HasMany(x => x.Comments).WithRequired().Map(m => m.MapKey("OwnerId"));
これはMetaDataException
指定されたスキーマが無効です。エラー:(10,6):エラー0019:タイプの各プロパティ名は一意である必要があります。プロパティ名'OwnerId'はすでに定義されています。(11,6):エラー0019:タイプの各プロパティ名は一意である必要があります。プロパティ名'OwnerId'はすでに定義されています。
3つのエンティティコメントの関連付けのうち2つを削除しても問題ありませんが、もちろんそれは解決策ではありません。
いくつかの詳細:
- DbContextジェネレーター項目を追加することにより、edmxから動作するDbContextモデル(「コードセカンド」)を作成することができます。(これは当面の回避策になります)。
- 動作中のコードファーストモデル(1つの関連付け)をedmx(
EdmxWriter
)にエクスポートすると、関連付けはストレージモデルにあるように見えますが、元のedmxでは概念モデルの一部です。
では、どうすればこのモデルをコードファーストで作成できますか?重要なのは、ストレージモデルではなく、概念モデルで関連付けをマップするようにコードファーストで指示する方法だと思います。