NHibernate ITransaction и чистая модель домена
-
21-09-2019 - |
Вопрос
Я пытаюсь написать свой Модель предметной области, насколько это возможно, не учитывает постоянство.Единственное, что я сейчас делаю, это отмечаю каждое свойство и метод. virtual
, поскольку NHibernate требует этого для отложенной загрузки.
В моем сборка модели предметной области Я определяю некоторые интерфейсы репозитория:
public interface IRepository<TEntity> where TEntity : EntityBase {
TEntity Get(int id);
/* ... */
}
public interface IProductRepository : IRepository<Product> { ... }
Тогда у меня есть сборка данных.Этот будет ссылаться на NHibernate, он знает о его существовании.Это сборка, реализующая эти интерфейсы репозитория:
public abstract class Repository<TEntity> : IRepository<TEntity> {
public TEntity Get(ind id) { ... }
/* ... */
}
public class ProductRepository : Repository<Product>, IProductRepository {
/* ... */
}
и так далее.
Теперь я хотел реализовать функциональность транзакций в мои репозитории.Для этого я бы добавил BeginTransaction
метод в моем интерфейсе IRepository.Однако я не могу определить тип возвращаемого значения как NHibernate.ITransaction
, поскольку я хочу, чтобы модель предметной области оставалась в неведении и не была вынуждена ссылаться на сборку NHibernate из сборки моей модели предметной области.
Что бы вы сделали?
Вы бы просто реализовали void BeginTransaction()
, а void Commit()
, и void RollBack()
методы интерфейса, и пусть реализация репозитория управляет ITransaction
объект внутри?
Или вы нашли бы способ разоблачить ITransaction
объект позволить клиенту управлять транзакцией напрямую с ним, а не использовать методы репозитория?
Спасибо!
Решение
Вы можете взглянуть на Острая архитектура в котором уже реализовано все, о чем вы говорите, включая универсальные репозитории с поддержкой транзакций.Решение заключается в том, что IRepository имеет свойство DbContext, которое инкапсулирует транзакции (на самом деле это интерфейс).Это первый из описанных вами вариантов (пользовательский интерфейс транзакций, скрывающий NHibernate).И это работает хорошо.
Я думаю, вы даже можете повторно использовать код S#arp, независимо от того, собираетесь ли вы использовать полную структуру.
Другие советы
Транзакции IMO всегда должны начинаться и заканчиваться в бизнес-логике, другими словами, транзакция должна начинаться на уровне обслуживания, а не на уровне репозитория, и репозиторий должен включаться в транзакцию, в идеале это должно быть сделано неявно.
Теперь, если вы используете NH, то если ваш сервис и репозитории используют один и тот же «сеанс» (что и должно быть), вы можете вызвать «BeginTransaction» на уровне сервиса и выполнить фиксацию или откат по мере необходимости:
Например, представьте себе метод в сервисе:
public void RegisterCustomer(Customer customer) { try { using(var transaction = _session.BeginTransaction()) { _customerRepository.Save(customer); _customerSurveyRepository.Save(customerSurvey); // DO What ever else you want... transaction.Commit(); } } catch (Exception exn) { throw new AMException(FAILED_REGISTRATION, exn); } }
То, как репозитории получают ссылку на один и тот же сеанс, можно решить путем внедрения конструкторов или использования SessionFactory для получения текущего сеанса...