Оптимизация NHibernate: загрузка всех данных из указанных таблиц

#nhibernate #caching #optimization #fluent-nhibernate #prefetch

#nhibernate #кэширование #оптимизация #свободно-nhibernate #предварительная выборка

Вопрос:

Сценарий: я создал ASP.NET Приложение MVC, которое управляет моими кулинарными рецептами. Я использую FluentNHibernate для доступа к данным из следующих таблиц:

  1. Пользователи
  2. Категории
  3. Рецепты
  4. Категории рецептов (таблица соединений «многие ко многим»)
  5. UserBookmarkedRecipes (таблица соединений «многие ко многим»)
  6. UserCookedRecipes (таблица соединений «многие ко многим»)

Вопрос: Есть ли какой-либо способ указать NHibernate загружать все данные из всех таблиц, перечисленных выше, и сохранять их в памяти / в кэше NHibernate, чтобы не требовалось никаких дополнительных запросов к базе данных?


Мотивация вопроса: Разнообразие отношений «многие ко многим» создает проблему, и такая оптимизация принесла бы большую пользу.

Примечание относительно данных: общий объем данных чрезвычайно мал. На данный момент речь идет менее чем о 100 рецептах.

Ответ №1:

Вместо предварительной загрузки всего, я бы предложил загружать один раз, а затем удерживать его по мере доступа.

NHibernate поддерживает два разных кэша и довольно хорошо справляется с синхронизацией их с вашим базовым хранилищем данных. По умолчанию он использует так называемый кэш «первого уровня» для каждого сеанса, но я не думаю, что это то, что вы хотите. Вы можете прочитать об отличиях на странице часто задаваемых вопросов nhibernate о кэшировании

Я подозреваю, что кэш второго уровня — это то, что вам нужно (это доступно во всем вашем приложении). Вам нужно будет получить поставщика кэша от NHContrib (загрузите версию, соответствующую вашей версии NHibernate). Поставщик SysCache2, вероятно, будет проще всего настроить для вашего сценария, поскольку ваше приложение будет ЕДИНСТВЕННЫМ, что записывает данные в базу данных. Если другие процессы будут выполнять запись, вам нужно будет убедиться, что все они используют один и тот же кэш в качестве промежуточного, если вы хотите, чтобы он оставался синхронизированным.

Кэш второго уровня настроен на время ожидания, которое вы можете установить на любое необходимое вам значение. Не думаю, что оно может быть бесконечным, но вы можете установить для него длительные периоды, если хотите (вероятно, не такая уж плохая идея время от времени возвращаться к DB). Если вы хотите предварительно загрузить все, вы можете просто получить доступ ко всем своим объектам из вашего метода Application_Start global.asax, но в этом не должно быть необходимости.

Вам нужно будет настроить вашу фабрику сеансов для использования кэша. Вызовите .Метод кэширования (…) при плавной настройке вашей фабрики сеансов он должен быть относительно понятным.

Вам также нужно будет установить кэш.ReadWrite () как в ваших сопоставлениях сущностей, так И в сопоставлениях отношений. Вы можете сделать это по соглашению или с помощью вызова Cache.ReadWrite() в ваших отображениях fluent.

Что-то вроде:

 public class RecipeMap : ClassMap<Recipe> {
    public RecipeMap () {
        Cache.ReadWrite();
        Id(x => x.Id);
        HasManyToMany(x => x.Ingredients).Cache.ReadWrite();
    }
}
  

При вызовах кэша в ваших сопоставлениях вы можете указать только для чтения или что-то еще, что вам может понадобиться. NonStrictReadWrite — интересная функция, она может значительно повысить производительность, но с повышенным риском чтения устаревших данных из кэша.

Комментарии:

1. Большое вам спасибо за ваш подробный ответ, я действительно ценю ваши усилия. Однако у меня есть вопрос: насколько я понял ваше описание кэша первого уровня, работающего для каждого сеанса, я бы счел этот метод кэширования более подходящим для моего сценария. В 99% случаев одновременно регистрируется только один пользователь; для доступа к любым данным этот пользователь должен быть авторизован. После того, как вы узнали больше о моем приложении, по-прежнему ли вы считаете, что NHContrib SysCache2 является более подходящим, и если да, то в чем, по вашему мнению, недостатки кэша первого уровня?

2. Обновление: Извините, я прочитал термин » сессия » и подумал о ASP.NET сеанс (который был бы тем, чего я хотел достичь). Теперь я понимаю разницу, и вы правы: такого поведения я не пытаюсь достичь.

3. Это зависит от вашей стратегии управления сеансом — обычно в веб-приложении время жизни сеанса составляет один запрос (например, NH-сессия, а не веб-сессия). Некоторые приложения просто получают новый сеанс для каждой страницы / элемента управления или даже для вызова nhibernate. Кэш первого уровня предназначен не для длительного использования, а для оптимизации в рамках одной единицы работы. Так что да, я думаю, что второй уровень все же более подходит для вашего сценария. Я бы полагался на первый уровень для этого типа кэширования только при использовании односессионного приложения winforms со встроенной базой данных, такой как SQLite.

4. Точно, я думал о веб-сессии, а не о NH-сессии. Я приму ваш ответ как можно скорее!