Fluent NHibernate で第 2 レベルのキャッシュ プロバイダー SysCache2 を使用し、標準的な流暢な構成 (一般的なアドバイスのようにクエリ キャッシュを有効にする) を使用し、テーブル ベースの依存関係を通常の方法で定義しています。
流暢:
config.Cache(c => c
.ProviderClass<NHibernate.Caches.SysCache2.SysCacheProvider>()
.UseQueryCache()
.UseSecondLevelCache()
.UseMinimalPuts()
)
Web.Config:
<cacheRegion name="User" relativeExpiration="7200">
<dependencies>
<tables>
<add name="User" databaseEntryName="OldClient" tableName="tbl_users" />
</tables>
</dependencies>
ユーザー マッピング:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("Users");
....
// caching
Cache.IncludeAll().ReadWrite().Region("Users");
}
}
単一のリクエストに対してすべてが期待どおりに実行されます。つまり、次のようになります。
Session<User>.Get()
NHibernate が IDでキャッシュする方法から予想されるとおりです。後続のリクエストはデータベースにヒットせず、データベース内のレコードを無効にするとエンティティが無効になり、次のリクエスト中に後続の SQL 呼び出しが発生します。大丈夫。
問題はクエリのキャッシュにあります。最初の例では、すべて正常に動作します。次のような呼び出しを実行します。
Session<User>.Query(item => item.Active == true)
期待どおりの SQL 呼び出しになります (SELECT * FROM Users WHERE Active = true)。その後の実行では、SQL は発生しません。偉大な。クエリ セットの 1 つのレコードがデータベースで変更されるまで。同じクエリを実行すると、SELECT N+1 になります。
SELECT * FROM Users WHERE ID = 1
SELECT * FROM Users WHERE ID = 2
SELECT * FROM Users WHERE ID = 3
SELECT * FROM Users WHERE ID = 4
...
解決策はありませんが、他の場所でこれへの参照を見つけました:
StackOverflow - NHibernate キャッシュ フェッチされた子コレクションを作成するにはどうすればよいですか? 「もう 1 つのポイント」セクションを参照してください
最後に「エンティティもキャッシュされる」ことを保証するAyende Caching Strategiesに言及
現時点でこれを回避できる唯一の方法は、リクエストごとにクエリキャッシュをクリアすることです。これにより、ほとんど役に立たなくなります。個々のレコードだけでなく、エンティティが無効化されたときに、クエリ キャッシュが特定のエンティティのすべてをクリアするために必要なこと。
何か案は?