NHibernate QueryCache в многопользовательской среде - PullRequest
2 голосов
/ 15 сентября 2011

Для нашего веб-приложения (ASP.NET) мы используем Fluent NHibernate (2.1.2) с кэшированием 2-го уровня не только для сущностей, но и для запросов (генерация запросов с помощью API критериев).Мы используем шаблон Session-Per-Request и одно приложение SessionFactory, поэтому кэш обслуживает все Nhibernate-Sessions.


Проблема:

У нас естьиметь дело с различными "Access-Rigths" для каждого пользователя в объектах данных в нашей устаревшей базе данных (Oracle), то есть представления ограничивают возвращаемые данные в соответствии с правами пользователя.Таким образом, существует ситуация, когда, например, одно и то же представление запрашивается по нашим критериям с точно таким же запросом, но возвращает другой набор результатов, в зависимости от прав пользователя.

Теперь, чтобы повысить производительность, упомянутый запроскэшируетсяНо это создает нам проблему, заключающуюся в том, что когда запрос запускается в результате действия пользователя A, он кэширует полученные идентификаторы, которые являются идентификаторами, к которым пользователь A имеет права доступа.Вскоре после этого тот же запрос запускается действием пользователя B, и Nhibernate затем выбирает кэшированные идентификаторы из первого вызова (от пользователя A) и пытается получить соответствующие объекты, к которым у пользователя 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)))

приводит к выражению where, которое всегда оценивается как true, но« меняет »запрос с точки зрения Nhibernate, поэтому он кэширует для отдельного« userName ».

Я знаю, это уродливо, и я не очень доволен этим. Кто-нибудь знает какой-нибудь альтернативный подход?

заранее спасибо.

...