且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在存储库模式中,事务边界应该在哪里?

更新时间:2023-02-13 16:48:50

工作单元绝对是要走的路.如果您将 SQL Server 与本地数据库一起使用,TransactionScope 将为您完成大部分繁重的工作;只要您在存储库之间共享会话(您是通过构造函数注入进行的,对吧......?),那么您就可以将它们嵌套到您的内心深处.默认情况下,如果有,它就加入环境"事务,如果没有,则启动一个新的事务,这正是您想要的工作单元的行为.

Unit of Work is definitely the way to go. If you're using SQL Server with a local database, TransactionScope will do most of the heavy lifting for you; as long as you share sessions between repositories (which you're doing through constructor injection, right...?), then you can nest these to your heart's content. By default, it enlists in the "ambient" transaction if there is one, and starts a new one if there isn't, which is exactly the behaviour you want for a unit of work.

所以您的存储库可能如下所示:

So your repositories might look like this:

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; }
}

然后您可以像这样执行完整的工作单元:

Then you can perform the complete unit of work like so:

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 库之一结合使用,并使用 TransactionScope 实现您的具体 UOW.

If you don't like TransactionScope or your environment prevents you from using it effectively then you can always implement your own UOW or use an existing implementation. Or if you're just an architectural neat-freak then you can do both - use a generic unit-of-work interface with one of the main DI libraries, and implement your concrete UOW using the TransactionScope.