Я провел остаток вечера, читая вопросы StackOverflow, а также некоторые записи в блоге и ссылки на эту тему. Все они оказались очень полезными, но я все еще чувствую, что они действительно не отвечают на мой вопрос.
Итак, я разрабатываю простое веб-приложение. Я хотел бы создать слой доступа к данным многократного использования, который позже я смогу использовать в других решениях. 99% из них будут веб-приложениями. Мне кажется, это хороший повод для изучения NHibernate и некоторых паттернов вокруг него.
Мои цели следующие:
- Я не хочу, чтобы уровень бизнес-логики НИЧЕГО знал ни о внутренней работе базы данных, ни о самом NHibernate.
- Я хочу, чтобы уровень бизнес-логики имел как можно меньше предположений относительно уровня доступа к данным.
- Я хочу, чтобы уровень доступа к данным был максимально простым и простым в использовании. Это будет простой проект, поэтому я не хочу ничего усложнять.
- Я хочу, чтобы уровень доступа к данным был как можно более ненавязчивым.
Запомнив все это, я решил использовать популярный шаблон репозитория. Я читал об этой теме на этом сайте и в различных блогах разработчиков, и я слышал кое-что о шаблоне единицы работы.
Я также осмотрелся и проверил различные реализации. (Включая FubuMVC contrib, SharpArchitecture и прочее в некоторых блогах.) Я обнаружил, что большинство из них работают по одному и тому же принципу: они создают «единицу работы», которая создается при создании экземпляра хранилища, они запускают транзакцию, делать вещи, и совершать, а затем начать все заново. Итак, только один ISession
на Repository
и все. Затем клиентский код должен создать экземпляр репозитория, сделать с ним что-нибудь и затем удалить.
Этот шаблон использования не удовлетворяет моей потребности быть максимально упрощенным, поэтому я начал думать о чем-то другом.
Я обнаружил, что в NHibernate уже есть что-то, что делает ненужными пользовательские реализации "единицы работы", и это класс CurrentSessionContext
. Если я правильно сконфигурирую контекст сеанса и проведу очистку, когда это будет необходимо, я пойду.
Итак, я придумал это:
У меня есть внутренний статический класс с именем NHibernateHelper
. Во-первых, у него есть статическое свойство, называемое CurrentSessionFactory
, которое при первом вызове создает фабрику сеансов и сохраняет ее в статическом поле. (Один ISessionFactory
на один AppDomain
достаточно хорош.) Затем, что более важно, он имеет статическое свойство CurrentSession
, которое проверяет, есть ли ISession
привязанный к текущему контексту сеанса, и, если нет, создает один, и связывает его, и он возвращается с ISession
, привязанным к текущему контексту сеанса.
Поскольку он будет использоваться в основном с WebSessionContext
(так, один ISession
на HttpRequest
, хотя для модульных тестов я настроил ThreadStaticSessionContext
), он должен работать без проблем. А после создания и привязки ISession
он подключает обработчик событий к событию HttpContext.Current.ApplicationInstance.EndRequest
, которое заботится об очистке ISession
после завершения запроса. (Конечно, он делает это только в том случае, если он действительно работает в веб-среде.)
Таким образом, при всей этой настройке NHibernateHelper
всегда сможет вернуть действительный ISession
, поэтому нет необходимости создавать экземпляр экземпляра репозитория, чтобы «единица работы» работала правильно. Вместо этого Repository
является статическим классом, который работает с ISession
из свойства NHibernateHelper.CurrentSession
и предоставляет функциональные возможности через него с помощью универсальных методов.
Так что, в основном, у меня получилось два очень ленивых синглета.
Мне любопытно, что вы думаете об этом?
Это правильный способ мышления или я совершенно не в курсе?
EDIT:
Я должен указать, что класс NHibernateHelper является внутренним, и в значительной степени невидим для потребителей хранилища.
Другая идея состоит в том, чтобы вызвать внедрение зависимости в решение, - создать интерфейс с именем IDataProvider
и создать один экземпляр этого при первом вызове класса Repository
. (Однако реализующий код должен быть в состоянии позаботиться и о концепции контекста.)
РЕДАКТИРОВАТЬ 2:
Кажется, что многим нравится моя идея, но в ответах еще слишком мало мнений по этому поводу.
Могу ли я предположить, что это правильный способ использования NHibernate? : P