modest violet

読者です 読者をやめる 読者になる 読者になる

modest violet

開発者としてのあれこれや、日々の雑記など

your future hasn't written yet. no one's has.
by Emmett Lathrop "Doc" Brown

【技術メモ】Entity Frameworkの保有情報が更新されない

Dev EntityFramework

EntityFrameworkに関して、何も考えずにDataTableとかと同じように考えて使用していたら、ドツボにはまった反省です。


似て非なるというのはこういうことなのかな・・・。違うか。

テンプレートに従う


ASP.NET MVCでスキャフォールディングを使用して作成した場合、こんな感じでコードが作成されます。

public class HogeController : Controller
{
    private HogeDbContext db = new HogeDbContext();

    public ActionResult Index()
    {
        return View();
    }
}


privateで宣言されたContextは、「まぁ、コネクション管理してるんでしょ」くらいな感覚で認識していました。



その後、検索やら保存やら行う処理を書いて、簡単な検索・更新が行える画面を作成し、同時処理違反の処理を実装する段階で問題が発覚しました。

public IEnumerable<hoge> GetAll()
{
    // 全件取得
    return db.hoge.Select(s => s);
}




「あれ?他で更新された内容が検索に反映されないゾ・・・???」



きちんと、保存前にもDBに対してSELECTを発行しているにも関わらず、返ってくる結果は古い情報・・・。

これってキャッシュが残っているよね?なんで??


DbContext内のオブジェクトは,Contextを破棄するまで残りつづけます.

4. データの挿入、読み出し、更新、削除 | densan-labs.net


んー、やっぱりそういう事か。じゃあ、リロード処理を組み込んでやればいいだけかな。



調べるとEntity Frameworkには「ChangeTracker」という変更追跡を処理するコンテキストプロパティーがあり、こいつが各Entryの「Reload」を投げられそうなので、こんな感じのリロード機能を付け足してみました。


public IEnumerable<hoge> GetAll()
{
    // リロード
    foreach (var entity in db.ChangeTracker.Entries())
    {
        entity.Reload();
    }

    // 全件取得
    return db.hoge.Select(s => s);
}


おお、ちゃんとリロードされたぞ。これで良し。


じゃあ、100件処理すると、どうなるのかな?




f:id:shin21sk:20160404155548j:plain


アカーンっ!!!宮川大輔 風)



ものの見事に100件分のクエリーが生成され、投げられたようです・・・。


どうも1件ずつクエリーを投げて更新するようで、複数レコードを処理する場合には向かないという事が分かりました。



結局のところ


スキャフォールディングで生成されたContextは使用せずに、必要最小限の範囲で使用するように変更しました。(usingを使用)



変更追跡の部分は、最初に取得した際の情報をAttach関数を使用して登録時に渡して判断するように修正。



絶対に他に良い方法はあるとは思うんですが、今の所はこれが自分の中では最適解なのかな、やっぱり。


vb6でConnectionを自分で管理していた時は、「Openして繋ぎっぱなしなんて悪」という認識だったしなぁ。


Repositoryパターンでのトランザクションの扱いと共に、悩ましい問題です。