コードファースト:独立したアソシエーション対外部キーアソシエーション?


102

新しいプロジェクトに取り掛かり、POCOを設計するたびに、私は自分自身と精神的な議論を交わしています。私は、外部キーの関連付けを支持するように見える多くのチュートリアル/コードサンプルを見てきました。

外部キー協会

public class Order
{
    public int ID { get; set; }
    public int CustomerID { get; set; } // <-- Customer ID
    ...
}

独立した団体とは対照的に:

独立した協会

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

私は過去にNHibernateを使用しており、OOを感じるだけでなく(遅延読み込みを使用して)独立した関連付けを使用して、IDだけでなく、Customerオブジェクト全体にアクセスできるという利点があります。これにより、たとえば、Orderインスタンスを取得Order.Customer.FirstNameして、明示的に結合を行わなくても実行できるため、非常に便利です。

要約すると、私の質問は次のとおりです。

  1. 独立したアソシエーションを使用することに重大な欠点はありますか?そして...
  2. ない場合、外部キーの関連付けを使用する理由は何でしょうか?

回答:


106

ORMを最大限に活用したい場合は、必ずエンティティ参照を使用します。

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

FKを使用してデータベースからエンティティモデルを生成すると、常にエンティティ参照が生成されます。それらを使用したくない場合は、手動でEDMXファイルを変更し、FKを表すプロパティを追加する必要があります。少なくともこれは、独立した関連付けのみが許可されているEntity Framework v1の場合でした。

エンティティフレームワークv4は、外部キーアソシエーションと呼ばれる新しいタイプのアソシエーションを提供します。独立キーと外部キーの関連付けの最も明らかな違いは、Orderクラスにあります。

public class Order
{
    public int ID { get; set; }
    public int CustomerId { get; set; }  // <-- Customer ID
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

ご覧のとおり、FKプロパティとエンティティ参照の両方があります。2種類の関連付けには、さらに違いがあります。

独立した協会

  • では、別のオブジェクトとして表されますObjectStateManager。独自のEntityState
  • アソシエーションを構築するときは、アソシエーションの両端からのエンティティが常に必要です
  • この関連付けは、エンティティと同じ方法でマッピングされます。

外部キー協会

  • では、個別のオブジェクトとして表されませんObjectStateManager。そのため、いくつかの特別なルールに従う必要があります。
  • 関連付けを作成する場合、関連付けの両端を必要としません。子エンティティと親エンティティのPKがあれば十分ですが、PK値は一意である必要があります。したがって、外部キーの関連付けを使用する場合は、リレーションで使用される新しく生成されたエンティティに一時的な一意のIDを割り当てる必要もあります。
  • この関連付けはマップされませんが、代わりに参照制約を定義します。

外部キーの関連付けを使用する場合は、エンティティデータモデルウィザードでモデル外部キー列を含めるを選択する必要があります

編集:

これら2つのタイプの関連付けの違いはあまり知られていないことがわかったのでこれをカバーする短い記事書いて、詳細とこれについての私自身の意見を述べました。


あなたの非常に洞察に満ちた答えに感謝します。また、正しい用語についての情報を提供してくれたことにも感謝します。これは、この主題に関するリソースと両方のテクニックの賛否両論を見つけるのに役立ちました。
Daniel Liuzzi

1
私はちょうどあなたの記事に出くわした、ラディスラフ。非常に興味深い資料であり、これら2つのアプローチの違いをさらに理解するための優れたリソースです。乾杯。
Daniel Liuzzi

1
@GaussZ:私が知っているように、EF4(FKアソシエーションが導入された)以降、関連付けの処理方法に変更はありませんでした。
Ladislav Mrnka 2013

1
これと他の答えはパフォーマンスの問題に影響を与えていないようです。ただし、セクション2.2によると、MSDN記事のビュー生成のパフォーマンスに影響を与える要因によると、独立した関連付けを使用すると、外部キーの関連付けよりもビュー生成のコストが増加するようです。
Veverke 16

1
@LadislavMrnka:上記の記事が機能していることへのリンクを再確認できますか?アクセスできません。
Veverke 16

34

両方を使う。そして、エンティティ参照を仮想化して、遅延読み込みを可能にします。このような:

public class Order
{
  public int ID { get; set; }
  public int CustomerID { get; set; }
  public virtual Customer Customer { get; set; } // <-- Customer object
  ...
}

これにより、不要なDBルックアップが節約され、遅延読み込みが可能になり、目的のIDがわかっている場合は、IDを簡単に確認/設定できます。両方を使用しても、テーブルの構造はまったく変わりません。


5
同意した。ラディスラフが示唆したように、これは私がやったことです。それは本当にあなたに両方の長所を与えます。すべてのプロパティが必要な場合はオブジェクト全体、PKのみが必要で残りは気にしない場合のID。
Daniel Liuzzi

9

独立した関連付けはAddOrUpdateSeedメソッドで通常使用されるものとうまく機能しません。参照が既存のアイテムである場合、再挿入されます。

// Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, Customer = customer };
db.Set<Order>().AddOrUpdate(order);

その結果、既存の顧客が再挿入され、新しい(再挿入された)顧客が新しい注文に関連付けられます。


外部キーの関連付けを使用してIDを割り当てない限り。

 // Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, CustomerId = customer.Id };
db.Set<Order>().AddOrUpdate(order);

予想される動作があり、既存の顧客は新しい注文に関連付けられます。


2
これは良い発見です。ただし、顧客を注文に添付するための回避策(および私は正しい方法だと思います)は、次のようにdbコンテキストからロードしvar order = new Order { Id = 1, Customer = db.Customers.Find(1) }; ます。または、Selectメソッドを使用して、dbコンテキストから顧客をロードできます。これは独立したアソシエーションで機能します。
tala9999

4

不要なルックアップを避けるために、オブジェクトアプローチを採用しています。プロパティオブジェクトは、ファクトリメソッドを呼び出してエンティティ全体を構築するときに(ネストされたエンティティの単純なコールバックコードを使用して)、同様に簡単に入力できます。メモリ使用量を除いて、目に見える欠点はありません(ただし、オブジェクトを正しくキャッシュしますか?)。したがって、ヒープの代わりにスタックを使用して、ルックアップを実行しないことでパフォーマンスを向上させるだけです。これが理にかなっているといいのですが。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.