次のように、子コレクションをフェッチする非常に単純な条件クエリがあります。
var order = Session.CreateCriteria<Order>()
.Add(Restrictions.Eq("Id", id))
.SetFetchMode("Customer", FetchMode.Eager)
.SetFetchMode("Products", FetchMode.Eager)
.SetFetchMode("Products.Category", FetchMode.Eager)
.SetCacheable(true)
.UniqueResult<Order>();
NH Profを使用して、コールドキャッシュを使用してデータベースへのラウンドトリップが(予想どおりに)1回だけ行われることを確認しました。ただし、連続して実行すると、次のようOrder
に、キャッシュからのみを取得し、グラフ内のすべての子エンティティに対してSELECT(N + 1)を使用してデータベースにアクセスします。
Cached query: SELECT ... FROM Order this_ left outer join Customer customer2 [...]
SELECT ... FROM Customer WHERE Id = 123;
SELECT ... FROM Products WHERE Id = 500;
SELECT ... FROM Products WHERE Id = 501;
...
SELECT ... FROM Categories WHERE Id = 3;
などなど。明らかに、クエリまたはグラフ全体をキャッシュするのではなく、ルートエンティティのみをキャッシュします。最初の「キャッシュされたクエリ」行には、実際にはjoin
想定されているすべての条件が含まれています。明らかに、エンティティだけでなく、クエリ自体も正しくキャッシュされています。
SysCache、SysCache2、さらにはHashTableキャッシュプロバイダーを使用してこれを試しましたが、常に同じ動作をするようです(NHバージョン3.2.0)。
グーグルは、次のような多くの古代の問題を明らかにしました。
- NH-195:子コレクションが第2レベルのキャッシュに保存されていません
- Syscache2第2レベルのキャッシュ:子coll。再クエリされたオブジェクト
- SysCacheとSysCache2の奇妙な違い
- NHibernate –不適切に適用されるキャッシング戦略に注意してください(Ayende-もちろん、彼はそれを修正する方法ではなく、何をすべきでないかについて言及するだけです...)
ただし、これらはすべてかなり前に修正されたようであり、使用するプロバイダーに関係なく、同じ悪い動作が発生します。
SysCacheとSysCache2に関するnhibernate.infoのドキュメントを読みましたが、不足しているものはないようです。cacheRegion
クエリに関係するすべてのテーブルのファイルに行を追加しようとしましWeb.config
たが、何も変更されません(そして、これらの要素はキャッシュを無効にするだけなので、とにかく問題にはなりません)。
すべてが修正/解決されたように見えるこれらの超古い問題のすべてで、これはおそらくNHibernateのバグではない可能性があると思います、それは私が間違っていることであるに違いありません。しかし、何ですか?
NHibernateのフェッチ命令を第2レベルのキャッシュと組み合わせるときに特別なことをする必要がありますか?ここで何が欠けていますか?