Я использую будущие запросы NHibernate в веб-приложении MVC 3 и стараюсь, чтобы весь доступ к моей базе данных происходил в моих контроллерах, а не в моих представлениях. Сайт представляет собой каталог ресурсов (описательные пометки), которые имеют коллекцию оценок «многие ко многим» и коллекцию тем «многие ко многим». Пользователи выбирают одну или несколько оценок и одну или несколько тем, а затем получают список подходящих ресурсов.
Чтобы заполнить форму поиска, я использую будущие запросы, чтобы получить все оценки и темы:
public Domain.SearchFormData GetSearchFormData()
{
// Get all grades and all topics using a multiquery.
IEnumerable<Grade> grades = Session.QueryOver<Grade>()
.Future();
IEnumerable<Topic> topics = Session.QueryOver<Topic>()
.Future();
var result = new SearchFormData();
result.Grades = grades;
result.Topics = topics;
return result;
}
Это очень просто, отлично работает и возвращает SearchFormData
, что является простым DTO. Этот запрос выполняется в контроллере, и результат не нуждается в дальнейшей обработке, поэтому он передается прямо в представление для отображения в виде списков флажков.
Но из-за ленивого выполнения будущих запросов доступ к базе данных не запускается до тех пор, пока представление не начнет перебирать списки. Некоторые считают, что это (например, NHibernate Profiler) - нет-нет, и они говорят, что к тому времени, когда представление начинает рендеринг, должен быть выполнен весь доступ к базе данных. Основная причина заключается в том, что при наличии скрытого SELECT N + 1 легко работать, если вы этого не сделаете.
Здесь это не относится; и класс, и тема - простые объекты без коллекций. Я не против того, что представление вызовет доступ к базе данных. Но это заставляет меня искать чистый, ясный способ инициировать все будущие запросы. Один из способов сделать это - получить доступ к результатам, например, скопировав IEnumerable
в список. Но на самом деле это не то, что мне нужно делать; Я просто хочу выполнить поставленные в очередь запросы.
Я думаю, что имеет смысл запускать триггер вне запроса выше. Мне могут понадобиться другие данные для отображения полного просмотра страницы, и я могу использовать другие будущие запросы для их получения. Например, на домашней странице также могут отображаться пять самых популярных ресурсов и общее количество ресурсов. Тогда контроллер будет вызывать несколько методов для накопления того, что ему нужно для представления, и будет наиболее эффективно выполнять все из них одновременно. Конечно, один из способов сделать это - развернуть мой GetSearchFormData
в GetAllHomePageData
и вернуть DTO с полями для всего на домашней странице. Но я использую форму поиска повсюду, а не только на главной странице. Так что я бы потерял какую-то хорошую модульность таким образом.