web-dev-qa-db-ja.com

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

私は新しいプロジェクトに取り掛かるたびに自分自身と精神的な議論を持ち、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を使用し、独立した関連付けを使用しました。これは、オブジェクト指向をより多く感じるだけでなく、(遅延読み込みを使用すると)IDだけでなくCustomerオブジェクト全体にアクセスできるという利点があります。これにより、たとえばOrderインスタンスを取得してからOrder.Customer.FirstName結合を明示的に行う必要がなく、非常に便利です。

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

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

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

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

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

Entity Framework 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つのタイプの関連付けの違いはあまり知られていないことがわかったので、 短い記事を書いた これについてさらに詳しく説明し、これについての私自身の意見を述べました。

106
Ladislav Mrnka

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

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

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

33
Seth Paulson

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

// 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);

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

8
Yuliam Chandra

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

4
CarneyCode