Является ли статический репозиторий правильным способом использования NHibernate? - PullRequest
13 голосов
/ 27 апреля 2010

Я провел остаток вечера, читая вопросы 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

Ответы [ 2 ]

2 голосов
/ 27 апреля 2010

Что бы это ни стоило, Sharp Architecture делает более или менее точно то, что вы предлагаете. В итоге выполняется один сеанс на HTTP-запрос (точнее, один сеанс на базу данных на HTTP-запрос). Ваш подход, безусловно, действителен и также обеспечивает один сеанс на запрос. Я скорее предпочитаю более чистый ОО-подход SharpArch через DI, чем использование статических репозиториев и вспомогательного класса.

1 голос
/ 28 апреля 2010

Мы смешали приложения ASP.NET/Windows Forms, и лучшее решение, которое я нашел, - это ручное внедрение зависимостей через конструктор репозитория. То есть каждый класс репозитория имеет единственный открытый конструктор, который требует ISession. Это позволяет приложению иметь полный контроль над единицами работы и границами транзакции. Это просто и эффективно. У меня также есть очень маленькая вспомогательная сборка NHibernate, которая настраивает фабрики сеансов и предоставляет методы для открытия обычного или контекстного сеанса.

Есть много вещей, которые мне нравятся в архитектуре S # arp, и я думаю, что стоит изучить, как она работает, но я обнаружил, что она чрезмерно разработана для моих вкусов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...