Entity Framework 5 Code FirstでこのEntityクラスを使用しています:
public class Survey
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string SurveyName { get; set; }
[Required]
public int ClientID { get; set; }
[ForeignKey("ClientID")]
public virtual Client Client { get; set; }
}
そして、コントローラーのCreateメソッドでこれを行います:
Survey entity = new Survey()
{
SurveyName = "Test Name",
ClientID = 4
};
db.Surveys.Add(entity);
db.SaveChanges();
Client c1 = entity.Client; //Why is this null?
Client c2 = db.Clients.Find(entity.ClientID); //But this isn't?
string s2 = c2.ClientName;
string s1 = c1.ClientName; //null reference thrown here
SaveChangesの後、クライアントナビゲーションプロパティはnullのままです。外部キーが存在するため、データベースからクライアントをロードする呼び出しを予期していました。なぜそうしなかったのですか?
[〜#〜] edit [〜#〜]ここでのコードは、コントローラーがDbContext
に依存していたときのものです。これが機能するようになってからまもなく、リポジトリと作業単位を使用するようにコードをリファクタリングしました。その動きの一部は、Create
を使用したいときにnew
を使用するのは間違っていると感じたという事実に基づいています。そのとき起こったことは、 リポジトリパターンを使用するときにプロキシが作成されるようにする方法 で問題が発生したことです。
親を作成した後にナビゲーションプロパティの遅延読み込みが機能するようにするには、Survey
演算子でnew
を作成するのではなく、コンテキストインスタンスを使用して作成する必要があります。関連するClient
を遅延ロードできる動的プロキシをインスタンス化します。それがDbSet<T>.Create()
メソッドの目的です:
_Survey entity = db.Surveys.Create();
entity.SurveyName = "Test Name";
entity.ClientID = 4;
db.Surveys.Add(entity);
db.SaveChanges();
Client c1 = entity.Client;
string s1 = c1.ClientName;
// will work now if a Client with ID 4 exists in the DB
_
強調するのは、DBからクライアントをロードするのは_entity.ClientID = 4;
_行またはdb.Surveys.Add(entity);
または_db.SaveChanges
_行ではなく、_Client c1 = entity.Client;
_行(遅延ロード)です。
@NicholasButlerが言ったように、SaveChanges
を呼び出すと、スズで言うことを行います-コードをデバッグすると、これを見ることができます:Intellitrace出力は、挿入/更新のために生成したSQLを表示しますが、その後の選択はありません。
(Include
メソッドを使用して)積極的なロードを行わない限り、関連するエンティティは取得時にロードされないため、それらを作成または更新することもできないのは当然です。
Entity Framework(バージョン4.1以降)は遅延読み込みをサポートしています。これが意味することは、それが有効になっている場合、Client c1 = entity.Client;
shouldClient
オブジェクトをロードします。明確にするために、この操作はSaveChanges
呼び出しに直接関連していません。
db.Configuration.LazyLoadingEnabled
はtrue
に設定されます。そうでない場合は、true
に設定してみて、Client c1 = entity.Client;
はまだnullです。
つまり、SaveChanges
を呼び出してもロードはトリガーされませんが、遅延ロードが有効になっている場合は、entity.Client
は、まだ読み込まれていない場合、エンティティの読み込みをトリガーする必要があります。
編集:
これについては以前に知っておくべきでしたが、あなたはSurvey entity
オブジェクト。その理由は、EFは、自分のクラスから派生したクラスを作成することで遅延ロードマジックを機能させるが、遅延ロードをサポートするためにvirtual
とマークされたプロパティをオーバーライドするからです。取得を実行するときにこれを行うため、entity
オブジェクトは、現状のまま遅延ロードを行いません。
SaveChanges
への呼び出しの直後にこれを試してください:
Survey entity2 = db.Surveys.Find(entity.ID);
Client c1 = entity2.Client;
これは、後の動作を示すはずです。
遅延読み込みを有効にするには、Survey
クラスのすべてのプロパティを仮想として定義する必要があります。
詳細については、 http://msdn.Microsoft.com/en-us/library/vstudio/dd468057(v = vs.100).aspx を参照してください。