Единица работы, безусловно, путь. Если вы используете SQL Server с локальной базой данных, TransactionScope
сделает большую часть тяжелой работы за вас; до тех пор, пока вы разделяете сеансы между репозиториями (что вы делаете с помощью инъекции в конструктор, верно ...?), вы можете вкладывать их в свое удовольствие. По умолчанию он включается в «внешнюю» транзакцию, если она есть, и запускает новую, если ее нет, и это именно то поведение, которое требуется для единицы работы.
Так что ваши репозитории могут выглядеть так:
public class UserRepository : IUserRepository
{
public UserRepository(ISession session)
{
this.Session = session;
}
public void Save(User user)
{
using (TransactionScope tsc = new TransactionScope())
{
Session.Save(user);
tsc.Complete();
}
}
protected ISession Session { get; set; }
}
public class OrderRepository : IOrderRepository
{
public OrderRepository(ISession session)
{
this.Session = session;
}
public void Save(Order order)
{
using (TransactionScope tsc = new TransactionScope())
{
Session.Save(order);
tsc.Complete();
}
}
protected ISession Session { get; set; }
}
Тогда вы можете выполнить всю единицу работы следующим образом:
User currentUser = GetCurrentUser();
using (TransactionScope tsc = new TransactionScope())
{
ISession session = SessionFactory.OpenSession();
Order order = new Order(...);
order.User = currentUser;
IOrderRepository orderRepository = GetOrderRepository(session);
orderRepository.Save(order);
currentUser.LastOrderDate = DateTime.Now;
IUserRepository userRepository = GetUserRepository(session);
userRepository.Save(currentUser);
tsc.Complete();
}
Если вам не нравится TransactionScope
или ваша среда мешает вам эффективно его использовать, тогда вы всегда можете реализовать свое собственное UOW или использовать существующую реализацию. Или, если вы просто изящный архитектор, то вы можете сделать и то, и другое - использовать универсальный интерфейс единицы работы с одной из основных библиотек DI и реализовать конкретное UOW, используя TransactionScope
.