2

私たちの Web アプリケーション (ASP.NET) では、Fluent NHibernate (2.1.2) を使用して、エンティティだけでなく、クエリ (基準 API を使用してクエリを生成する) に対しても第 2 レベルのキャッシュを使用しています。Session-Per-Request パターンと 1 つの SessionFactory アプリケーション全体を使用しているため、キャッシュはすべての Nhibernate-Sessions を提供します。


問題:

従来のデータベース (Oracle) のデータ オブジェクトでは、ユーザーごとに異なる "アクセス権" に対処する必要があります。つまり、ビューはユーザー権限ごとに返されるデータを制限します。したがって、たとえば、まったく同じクエリを使用して基準によって同じビューがクエリされますが、ユーザー権限に応じて異なる結果セットが返されるという状況があります。

ここで、パフォーマンスを向上させるために、前述のクエリがキャッシュされます。しかし、これはユーザー A のアクションからクエリが最初に起動されたときに、ユーザー A がアクセス権を持つ ID である結果の ID をキャッシュするという問題を引き起こします。その直後に、同じクエリがユーザー B のアクションから起動され、Nhibernate は (ユーザー A からの) 最初の呼び出しからキャッシュされた ID を選択し、ユーザー B がアクセス権を持っていない対応するエンティティを取得しようとします (または、すべてではないかもしれません)。イベントリスナーで権利をチェックしているため、前述のケースではアプリケーションがアクセス権例外をスローします。


考え:

クエリをキャッシュしないことは、これに対するオプションになる可能性があります。しかし、パフォーマンスは明らかに私たちのアプリケーションの問題であるため、ユーザーごとにクエリをキャッシュすることが本当に望ましいでしょう。

ユーザーごとに SessionFactory を作成して、ユーザーごとにキャッシュを作成することも考えました。しかし、これは明らかにリソースに影響を与え、やややり過ぎであり、正直なところオプションではありません。複数のユーザー (ユーザー グループを考えてください) がアクセスし、操作する必要があるエンティティが存在するためです。 「個々のキャッシュ」などの古いデータに関する問題。だから、それはいけません。

これに対する有効な解決策は何ですか?そのような状況の「ベストプラクティス」のようなものはありますか?


考え:

昨日これに行き詰まり、解決策が見つからなかったので、寝て、今日、ある種の「ハック」を思いつきました。

NHibernate はクエリ テキストとパラメータ (「句」) によってクエリをキャッシュするため、クエリの署名でユーザーに依存するものを「密輸」する方法を考えました。これにより、ユーザーごとにすべてのクエリがキャッシュされますが、クエリ自体を変更します (クエリの結果に関して)。

したがって、「創造性」が私をこれに導きました(サンプルコード):

string userName = GetCurrentUser();
ICriteria criteria = session.CreateCriteria(typeof (EntityType))
            .SetCacheable(true)
            .SetCacheMode(CacheMode.Normal)
            .Add(Expression.Eq("PropertyA", 1))
            .Add(Expression.IsNotNull("PropertyB"))
            .Add(Expression.Sql(string.Format("'{0}' = '{0}'", userName)));
return criteria.List();

この行:

.Add(Expression.Sql(string.Format("{0} = {0}", userName)))

これは常に true と評価されますが、Nhibernate の観点からクエリを「変更」するため、個別の「userName」ごとにキャッシュされます。

私は知っています、それはちょっと醜いです、そして私はそれに本当に満足していません. 誰かが別のアプローチを知っていますか?

前もって感謝します。

4

0 に答える 0