NHibernate QueryCache в многопользовательской среде

Для нашего веб-приложения (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".

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

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

0 ответов

Другие вопросы по тегам