DbContextのTracking設定をすべてのエンティティに設定する

テストプログラムなどで更新処理を実行するときにContextのTrackingが有効な場合、Contextから更新後のデータを取得するときに最初に取得した情報をContextが保持していてテストがFailになる事があります。忘れた頃に発生する事象で、たいてい急いでいるときにテスト対象のプログラムは正しいけどテストが通らないというつらい状況になったりします。

このようなケースでは最初にエンティティを取得するときにAsNoTrackingを設定すればOKです。

 var personCustomer = CustomerContext.Context.Customers.AsNoTracking().Include(c => c.Person).Include(c => c.Organization)
                .First(c => c.Person != null);

とはいうものの、テストのように基本データを参照しかしないケースではデフォルトとしてAsNoTrackingを設定したいですよね。むしろ、TrackingしたいときにだけAsTrackingを設定することで余計なハマりをなくしたいわけです。

そこでContext単位でAsnoTrackingを一括で設定できる方法はないだろうかということになりますが、以下の通り設定すればContextに含まれるエンティティの取得がすべてTracking対象ではなくなります。

 Context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

参考

以下の公式ドキュメントにもあるようにReadonlyとしてエンティティを使用する場合にはChangeTrackerの生成コストが小さくなるためおすすめのようです。

ChangeTracker Class (Microsoft.EntityFrameworkCore.ChangeTracking) | Microsoft Docs

Gets or sets the tracking behavior for LINQ queries run against the context. Disabling change tracking is useful for read-only scenarios because it avoids the overhead of setting up change tracking for each entity instance. You should not disable change tracking if you want to manipulate entity instances and persist those changes to the database using SaveChanges(). This method sets the default behavior for the context, but you can override this behavior for individual queries using the AsNoTracking(IQueryable) and AsTracking(IQueryable) methods. The default value is TrackAll. This means the change tracker will keep track of changes for all entities that are returned from a LINQ query.

大人数で開発するときにはこの手のはまりは人数分のコストになるので、技術的に解決できるところはあらかじめ解決しておきたいですね。

追記

Npgsqlを利用している場合には、テスト対象データのバージョン番号を取得するためにはAsTrackingを設定する必要があります。

C#プログラマーのための 基礎からわかるLINQマジック!

C#プログラマーのための 基礎からわかるLINQマジック!