トップ回答者
entity frameworkのDbContextの閉じるタイミング

質問
-
いつもお世話になっております。
ASP.NET MVC(ver4)でEntity Framework(ver5)を使って開発しています。
操作で不明な点がありまして、質問させて頂きます。
○不明点
コントローラー側では以下のようにusginで囲んで
処理が終わったら開放するようにしています。
using (var context = new TestEntities()) {
ーーー処理ーーーー
}
上記コードが問題になる部分があります。
それがview側で
@foreach (var item in Model)
{
ーーー処理ーーー
}
と行うと「操作を完了できません。DbContext は破棄されています。」とエラーが表示されます。
View側でもModelを使う場合はどこでDbContexを破棄すれば良いでしょうか?
まだ基礎が理解出来ていないようです。
お手数おかけしますが、ご教授頂きたくお願い致します。
回答
-
LINQ で重要な概念に遅延実行というのがあるんですが、そのあたりがきちんと理解できていないように思えます。
> Entity FrameworkをLinqでselectした結果が「IQueryable」なので、そのデータをそのまま使っています。
IQueryable というのは結果のデータではなく、データを取得するための「式」を保持している状態です。
ここから実際のデータにさわろうとしたタイミングでこの式が評価され、DBへのSQL文の発行やデータの取得が行われます。
これが遅延実行といわれる動きです。今だとModel中では「式」の状態で持っているだけなので、Viewのなかでデータに触ろうとしたときにSQL文を発行しようとしてエラーになっている、という状態におちいってしまっているのだと思います。
前にも書いてますが、データの取得はViewに渡す前におこなってください。
IQueryableで持っている式に .ToList() を追加すると、これはデータを取得してListの形式で保持することになるので、とりあえず今のエラーは回避できるようになりそうな気がします。
まぁ、これだけで十分かというと疑問ではありますが。あおい情報システム株式会社 小野修司(どっとねっとふぁん)
- 回答としてマーク GacktFun 2014年7月16日 5:23
すべての返信
-
LINQ で重要な概念に遅延実行というのがあるんですが、そのあたりがきちんと理解できていないように思えます。
> Entity FrameworkをLinqでselectした結果が「IQueryable」なので、そのデータをそのまま使っています。
IQueryable というのは結果のデータではなく、データを取得するための「式」を保持している状態です。
ここから実際のデータにさわろうとしたタイミングでこの式が評価され、DBへのSQL文の発行やデータの取得が行われます。
これが遅延実行といわれる動きです。今だとModel中では「式」の状態で持っているだけなので、Viewのなかでデータに触ろうとしたときにSQL文を発行しようとしてエラーになっている、という状態におちいってしまっているのだと思います。
前にも書いてますが、データの取得はViewに渡す前におこなってください。
IQueryableで持っている式に .ToList() を追加すると、これはデータを取得してListの形式で保持することになるので、とりあえず今のエラーは回避できるようになりそうな気がします。
まぁ、これだけで十分かというと疑問ではありますが。あおい情報システム株式会社 小野修司(どっとねっとふぁん)
- 回答としてマーク GacktFun 2014年7月16日 5:23
-
どういうコードでやっているのか書いてないので想像ですが、以下のページの AddressController.cs のコードで var db = ... から return View(list); までを using ブロックで囲んだところ、Index.aspx の foreach で例外がスローされるというようなことでしょうか?
10 行でズバリ!! ASP.NET MVC を構成する各コンポーネントとネーミング ルール (C#)
http://code.msdn.microsoft.com/10-ASPNET-MVC-C-8566eeb5/そうだとすると、foreach のところでエンティティデータオブジェクト経由 DB に接続してデータを取りに行くものの、その前に using ブロックを抜けたところで Dispose されていて View では使用できなくなっているので、例外がスローされると言うことだと思います。
なので、上記ページのサンプルコードのような形にしている限りは(即ち、View でエンティティデータオブジェクトを使用する限りは)、Controller でエンティティデータオブジェクトを Dispose することはできません。
View で Dispose できないこともないですが、そんなことはしなくても、ガベージコレクタに任せておけば良いと思います。
#質問する時は、具体的にどういう手順でやっているのか書いてください。例えば、上に書いたように、Web にあるチュートリアルなどのサンプルコードを例に取るなどして。そうしないと、掲示板に書いてある情報が全ての回答者にとっては、質問者さんの状況は理解し難いです。