1. ホーム
  2. c#

[解決済み】Entity Frameworkのモデル定義でクラスプロパティに「virtual」を使用する理由は?

2022-04-03 07:50:20

質問

以下のブログで http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

ブログには、以下のコードサンプルが掲載されています。

public class Dinner
{
   public int DinnerID { get; set; }
   public string Title { get; set; }
   public DateTime EventDate { get; set; }
   public string Address { get; set; }
   public string HostedBy { get; set; }
   public virtual ICollection<RSVP> RSVPs { get; set; }
}

public class RSVP
{
   public int RsvpID { get; set; }
   public int DinnerID { get; set; }
   public string AttendeeEmail { get; set; }
   public virtual Dinner Dinner { get; set; }
}

を使用する目的は何ですか? virtual クラスでプロパティを定義するときは? また、どのような効果があるのでしょうか?

どのように解決するのですか?

Entity Framework が仮想プロパティの周りにプロキシを作成し、プロパティがレイジーローディングとより効率的な変更追跡をサポートできるようにします。参照 Entity Framework 4.1 POCO Code First で virtual キーワードはどのような効果があるのですか? を参照してください。

編集して、"create a proxy around"を明確にしました。 create a proxy around"というのは、特にEntity Frameworkが行うことについて言及しています。Entity Framework は、遅延ロードと効率的な変更追跡をサポートするために、ナビゲーションプロパティを仮想としてマークすることを要求します。参照 POCOプロキシを作成するための要件 .

Entity Frameworkは、この機能をサポートするために継承を使用します。そのため、ベースクラスのPOCOで特定のプロパティを仮想とマークする必要があります。それは文字通り、あなたのPOCO型から派生した新しい型を作成します。つまり、あなたのPOCOはEntity Frameworkが動的に作成するサブクラスの基本型として動作しているのです。それが私が"create a proxy around"で意味したことです。

Entity Frameworkが作成する動的に生成されるサブクラスは、静的なコンパイル時ではなく、実行時にEntity Frameworkを使用することで明らかになります。そして、Entity Frameworkの遅延ロードまたは変更追跡機能を有効にした場合のみです。Entity Framework の遅延ロードや変更追跡機能を使わないことを選択した場合 (これはデフォルトではありません)、ナビゲーションプロパティを仮想として宣言することは必要ありません。その場合、Entity Framework が "eager loading" と呼ぶものを使用するか、複数のデータベースクエリにわたって関連する型を手動で取得して、それらのナビゲーションプロパティを自分でロードする責任を負います。しかし、多くのシナリオで、ナビゲーションプロパティの遅延ロードと変更追跡機能を使用することができますし、使用する必要があります。

もし、あなたが独立したクラスを作成し、プロパティを仮想とマークし、Entity Frameworkの範囲外の独自のアプリケーションでそのクラスのインスタンスを単に構築して使用するとしたら、仮想プロパティはそれ自体では何も得られないでしょう。

プロパティが仮想とマークされる理由を説明するために編集する

などのプロパティがあります。

 public ICollection<RSVP> RSVPs { get; set; }

はフィールドではないので、そのように考えるべきではありません。これらはゲッターやセッターと呼ばれ、コンパイル時にメソッドに変換されます。

//Internally the code looks more like this:
public ICollection<RSVP> get_RSVPs()
{
    return _RSVPs;
}

public void set_RSVPs(RSVP value)
{
    _RSVPs = value;
}

private RSVP _RSVPs;

そのため、Entity Frameworkで使用するために仮想とマークされています。これは、動的に作成されたクラスが、内部で生成された getset 関数を使用します。もし、ナビゲーション・プロパティ・ゲッター/セッターがEntity Frameworkの使用で機能しているなら、それらを単なるプロパティに修正して再コンパイルし、Entity Frameworkがまだ適切に機能するかどうかを確認してください。

 public virtual ICollection<RSVP> RSVPs;