レイジーローディングで参照先のエンティティを読込む方法
Entity Framework のコードファーストにおけるデータモデリングでは、 ナビゲーションプロパティを設定することで簡単にバックエンドのデータベースでリレーションを設定できることは、 エンティティフレームワーク・コードファーストで作成されたデータベースを確認する でみました。
裏側でどんなデータができたか、というような話をいつまでもするのもいずれは余計な話になるのかもしれませんが、 (そんなことを意識せずに最適化されたデータベースが裏で使わるに越したことはないですよね) 現状はある程度、いつどんなデータがロードされるかということを開発者側が意識しつつ、 効率の良いコードを書いていくしかないわけです。
レイジーローディングとダイナミックプロキシー
エンティティーフレームワークでは、ナビゲーションプロパティを設定してあっても、デフォルトでは自動的にはその参照先は読み込まれません。
これはレイジーローディング (Lazy Loading) というもので、デフォルトでこの設定 (DbContext.Configuration.LazyLoadingEnabled) が true なのです。
少し細かいことを言えば、エンティティ・フレームワークはダイナミックプロキシー (dynamic proxy) を用いてレイジーローディングを実装しています。
エンティティーフレームワークがクエリの結果を返すとき、 フレームワークはそのクラスのインスタンスを作成し、データベースから返された値でそのインスタンスをポピュレートします。 エンティティフレームワークは実行時にモデルとなる POCO クラスから継承される新しいタイプを作ってこれを 行うのですが、これが POCO クラスのダイナミックプロキシーと呼ばれます。
ダイナミックプロクシーは POCO クラスのナビゲーションプロパティをオーバーライドして、 さらにロジックを追加してデータベースからデータを取得します。
ダイナミックプロクシーは POCO クラスから継承されていますので、POCO クラスを扱うのと同じ作法で扱うことができる、というわけです。
参照先の読み込み
裏側で何が動いているかはこのくらいにして、参照先を必要に応じて読み込みたい場合、どうすればよいかみてみましょう。
まずは問題設定をおさらいします。
以前の例と同じです。会社 (Company) と従業員 (Employee) のエンティティーがあって、 会社と従業員が 1:n の関係になっています。Employee クラスには Company へのナビゲーションプロパティが設定されています。
裏のデータベースは次のようになります。
ここで Employee オブジェクトを取得して、参照先である Company (ナビゲーション) プロパティにアクセスしてみます。
Company プロパティには値が設定されておらず、null 参照の例外がでてしまいました。
あるオブジェクトからその参照先を読み込むには、次のように Reference メソッドを利用します。 Reference メソッドで、このエンティティーから他の (ナビゲーションプロパティで指定した) エンティティーを参照するための、 参照ナビゲーションプロパティを表すオブジェクトを取得できます。
このオブジェクトの Load メソッドを呼ぶことによって、参照先をロードすることが可能です。
このように Load メソッドを呼べばこの例で言えば Company プロパティが正しく設定されます。