大数跨境
0
0

数据一致性保障:Unit of Work模式在.NET中的实战指南

数据一致性保障:Unit of Work模式在.NET中的实战指南 dotNET跨平台
2025-11-16
2
导读:当您构建一个连接数据库的应用程序(如ASP.NET Core Web API)时,经常需要一起执行多个数据

 

当您构建一个连接数据库的应用程序(如ASP.NET Core Web API)时,经常需要一起执行多个数据库操作。
例如,当用户下订单时,您可能需要:

  • • 创建新的订单记录
  • • 更新产品库存
  • • 保存支付记录

所有这些操作应该一起发生。如果其中一个失败,其他操作也不应该被保存。
这正是Unit of Work(工作单元)模式变得非常有用的地方。

什么是Unit of Work模式?
Unit of Work模式是一种设计模式,用于在操作数据库时帮助管理事务。

它跟踪在业务过程中所做的所有更改,然后在单个操作中将它们提交到数据库。如果任何操作失败,它可以回滚所有内容——这样您的数据就能保持干净和一致。

您可以把它想象成购物车。
您可以从购物车中添加或移除商品(您的操作),但实际的"保存"只在您结账时(提交)发生。如果在结账过程中出现问题,什么都不会被购买,购物车保持原样。

没有Unit of Work时的问题
让我们先看看不使用此模式时会发生什么。

public classProductService
{
    privatereadonly ProductRepository _productRepository;
    privatereadonly OrderRepository _orderRepository;

    public ProductService(ProductRepository productRepository, OrderRepository orderRepository)
    {
        _productRepository = productRepository;
        _orderRepository = orderRepository;
    }
    public void CreateOrder(Order order, Product product)
    {
        _orderRepository.Add(order);
        _productRepository.Update(product);

        // 每个存储库单独保存
        _orderRepository.Save();
        _productRepository.Save();
    }
}

乍一看,这看起来没问题。但存在一个大问题。每个存储库都在单独保存更改。

如果订单保存成功,但由于数据库错误导致产品更新失败,会发生什么?

您的数据库现在有半完成的数据——订单存在,但产品库存没有减少。在真实系统中,这很容易导致严重的数据问题。

解决方案:使用Unit of Work模式
Unit of Work模式通过允许您将多个数据库操作分组到单个事务中来修复此问题。这意味着如果某一部分失败,所有内容都会自动回滚。

让我们看看如何在.NET中逐步构建它。

步骤1:为Unit of Work创建接口
我们首先定义一个简单的接口,列出我们的存储库和一个Complete()方法来保存所有更改。

public interface IUnitOfWork : IDisposable
{
    IProductRepository Products { get; }
    IOrderRepository Orders { get; }
    int Complete();
}

这里:

  • • Products和Orders是存储库属性。
  • • Complete()将所有更改提交到数据库。
  • • Dispose()确保资源被正确清理。

步骤2:实现Unit of Work类
现在我们实现这个接口。这个类将持有一个共享给所有存储库的DbContext。

public classUnitOfWork : IUnitOfWork
{
    privatereadonly AppDbContext _context;

    public IProductRepository Products { getprivateset; }
    public IOrderRepository Orders { getprivateset; }

    public UnitOfWork(AppDbContext context)
    {
        _context = context;
        Products = new ProductRepository(_context);
        Orders = new OrderRepository(_context);
    }

    public int Complete()
    {
        // 一次性保存所有更改
        return _context.SaveChanges();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

现在,所有存储库共享一个DbContext。这意味着每个操作都在同一个事务内发生。当您调用Complete()时,所有更改一起保存。

步骤3:在服务层使用Unit of Work
让我们在服务类中使用它。

public classOrderService
{
    privatereadonly IUnitOfWork _unitOfWork;

    public OrderService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public void CreateOrder(Order order, Product product)
    {
        _unitOfWork.Orders.Add(order);
        _unitOfWork.Products.Update(product);
        _unitOfWork.Complete(); // 一起保存所有更改
    }
}

现在您可以看到区别。两个存储库都执行操作,但只通过Unit of Work调用一次SaveChanges()。

如果保存失败,数据库中不会存储任何数据,从而确保一致性。

内部工作原理
Unit of Work管理数据库上下文的单个实例。当您执行Add()、Update()或Delete()等操作时,这些更改由Entity Framework在内存中跟踪。

当您调用Complete()时,Unit of Work告诉EF Core在一个事务内提交所有更改。

如果在SaveChanges()期间发生错误,EF Core会自动回滚事务——意味着不会保存部分数据。

使用EF Core上下文的示例
如果您使用Entity Framework Core,您的DbContext已经像一个小型的Unit of Work。
但是,当您有多个存储库时,使用自定义的Unit of Work可以增加结构并保持代码清洁。

这是一个示例AppDbContext:

public class AppDbContext : DbContext
{
    public DbSet<Product> Products { getset; }
    public DbSet<Order> Orders { getset; }
}

通过将此AppDbContext注入到UnitOfWork中,所有存储库共享相同的上下文。
这使得多个更改可以作为一个事务提交。

使用Unit of Work模式的优势
在.NET项目中使用此模式有几个强有力的理由。

1. 数据一致性
所有数据库更改作为一个单元处理。如果一个操作失败,所有内容都会回滚。
这保证了您的数据始终一致。

2. 更清晰的代码
您只需从Unit of Work调用一次SaveChanges(),而不是在每个存储库中调用。
这使您的存储库专注于数据访问,服务专注于业务逻辑。

3. 更易维护
当项目增长时,您可以轻松地在Unit of Work中添加更多存储库。
您不必修改其余代码——只需更新Unit of Work实现。

4. 更易测试
在单元测试期间,您可以模拟Unit of Work和存储库。
这有助于您测试业务逻辑而无需实际接触数据库。

5. 跨多个存储库的单一事务
这是主要好处。
当您保存相互依赖的多个实体时,您希望要么全部保存,要么全部不保存——Unit of Work确保了这一点。

真实示例:电子商务订单处理
让我们看一个简单的真实案例。
您正在构建一个电子商务系统,客户在其中下订单。

当下订单时,会发生三件事:

  • • 创建订单记录
  • • 更新产品数量
  • • 保存支付日志

没有Unit of Work,您需要分别保存每一项。
但使用Unit of Work:

_unitOfWork.Orders.Add(order);
_unitOfWork.Products.Update(product);
_unitOfWork.Payments.Add(payment);
_unitOfWork.Complete();

所有三个操作将一起保存。
如果其中一个失败——例如,支付保存失败——所有其他更改将被回滚。
这确保您的系统永远不会出现不完整的数据。


Unit of Work模式是处理数据库的.NET应用程序中最重要的模式之一。
它帮助将多个数据库操作作为单个事务进行管理。
当与Repository模式一起使用时效果最佳,在业务逻辑和数据访问代码之间提供了清晰的分离。

 


【声明】内容源于网络
0
0
dotNET跨平台
专注于.NET Core的技术传播。在这里你可以谈微软.NET,Mono的跨平台开发技术。在这里可以让你的.NET项目有新的思路,不局限于微软的技术栈,横跨Windows,
内容 876
粉丝 0
dotNET跨平台 专注于.NET Core的技术传播。在这里你可以谈微软.NET,Mono的跨平台开发技术。在这里可以让你的.NET项目有新的思路,不局限于微软的技术栈,横跨Windows,
总阅读14.0k
粉丝0
内容876