首页 > 编程语言 >在 ASP.NET Core 中使用 EF Core 进行开启事务工作单元(Unit of Work) 仓储层,服务层模式

在 ASP.NET Core 中使用 EF Core 进行开启事务工作单元(Unit of Work) 仓储层,服务层模式

时间:2024-10-29 17:20:25浏览次数:3  
标签:Core Task Work ASP unitOfWork context async public await

在 ASP.NET Core 中使用 Entity Framework Core 实现一个带有事务的工作单元(Unit of Work)模式的仓储层和服务层,可以确保在执行多个数据库操作时具有原子性。这样,即使某个操作出现错误,所有操作也可以回滚。

以下是如何实现这个模式的详细步骤:

  1. 定义实体类
    我们首先定义一个简单的实体类,例如 Product:
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}
  1. 定义数据库上下文
    定义一个继承自 DbContext 的数据上下文类:
public class ApplicationDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }
}
  1. 定义仓储接口和实现
    创建一个通用的仓储接口并实现它:
public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    Task<T> GetByIdAsync(int id);
    Task<IEnumerable<T>> GetAllAsync();
}

public class Repository<T> : IRepository<T> where T : class
{
    private readonly ApplicationDbContext _context;
    private readonly DbSet<T> _dbSet;

    public Repository(ApplicationDbContext context)
    {
        _context = context;
        _dbSet = context.Set<T>();
    }

    public void Add(T entity) => _dbSet.Add(entity);
    public void Update(T entity) => _dbSet.Update(entity);
    public void Delete(T entity) => _dbSet.Remove(entity);
    public async Task<T> GetByIdAsync(int id) => await _dbSet.FindAsync(id);
    public async Task<IEnumerable<T>> GetAllAsync() => await _dbSet.ToListAsync();
}
  1. 定义工作单元接口和实现,支持事务
    在工作单元实现中,我们将包含事务处理。可以使用 IDbContextTransaction 来控制事务:
public interface IUnitOfWork : IDisposable
{
    IRepository<T> Repository<T>() where T : class;
    Task<int> SaveChangesAsync();
    Task BeginTransactionAsync();
    Task CommitTransactionAsync();
    Task RollbackTransactionAsync();
}

public class UnitOfWork : IUnitOfWork
{
    private readonly ApplicationDbContext _context;
    private IDbContextTransaction _transaction;

    public UnitOfWork(ApplicationDbContext context)
    {
        _context = context;
    }

    public IRepository<T> Repository<T>() where T : class
    {
        return new Repository<T>(_context);
    }

    public async Task BeginTransactionAsync()
    {
        _transaction = await _context.Database.BeginTransactionAsync();
    }

    public async Task CommitTransactionAsync()
    {
        await _transaction.CommitAsync();
    }

    public async Task RollbackTransactionAsync()
    {
        await _transaction.RollbackAsync();
    }

    public async Task<int> SaveChangesAsync()
    {
        return await _context.SaveChangesAsync();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}
  1. 创建服务层
    服务层使用工作单元和仓储,确保在需要时可以开启和提交事务:
public interface IProductService
{
    Task<Product> CreateProductAsync(Product product);
    Task<bool> DeleteProductAsync(int id);
}

public class ProductService : IProductService
{
    private readonly IUnitOfWork _unitOfWork;

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

    public async Task<Product> CreateProductAsync(Product product)
    {
        await _unitOfWork.BeginTransactionAsync();
        try
        {
            _unitOfWork.Repository<Product>().Add(product);
            await _unitOfWork.SaveChangesAsync();
            await _unitOfWork.CommitTransactionAsync();
        }
        catch
        {
            await _unitOfWork.RollbackTransactionAsync();
            throw; // 可以抛出异常,交由上层处理
        }
        return product;
    }

    public async Task<bool> DeleteProductAsync(int id)
    {
        await _unitOfWork.BeginTransactionAsync();
        try
        {
            var product = await _unitOfWork.Repository<Product>().GetByIdAsync(id);
            if (product == null) return false;

            _unitOfWork.Repository<Product>().Delete(product);
            await _unitOfWork.SaveChangesAsync();
            await _unitOfWork.CommitTransactionAsync();
        }
        catch
        {
            await _unitOfWork.RollbackTransactionAsync();
            throw; // 处理异常
        }
        return true;
    }
}
  1. 在 Startup 类中注册服务
    在 Startup.cs 文件中,进行依赖注入的配置:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddScoped<IUnitOfWork, UnitOfWork>();
    services.AddScoped<IProductService, ProductService>();
}
  1. 使用服务层
    最后,创建一个控制器来使用服务层:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    [HttpPost]
    public async Task<IActionResult> Create(Product product)
    {
        var createdProduct = await _productService.CreateProductAsync(product);
        return CreatedAtAction(nameof(GetById), new { id = createdProduct.Id }, createdProduct);
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id)
    {
        var result = await _productService.DeleteProductAsync(id);
        if (!result) return NotFound();
        return NoContent();
    }
}

重要注意事项
事务的使用:每次添加或删除产品时都会开启事务(BeginTransactionAsync),并在操作成功时提交事务(CommitTransactionAsync),在操作失败时回滚事务(RollbackTransactionAsync)。

异常处理:在服务层中,建议捕获异常并进行适当处理,可以记录日志或抛出自定义异常。

分离关注点:将数据访问逻辑、业务逻辑和控制逻辑分开,有助于提升代码的可维护性和可测试性。

通过这个模式,你可以确保在执行多个数据库操作时的原子性,保持数据的一致性和完整性。

标签:Core,Task,Work,ASP,unitOfWork,context,async,public,await
From: https://www.cnblogs.com/zy8899/p/18513987

相关文章

  • C#03-.NET Core学习笔记
    @目录1.关于.NET1.什么是.NET?2.什么是.NETFrameWork?3.什么是.NETCore?4.NETCore的优点2.异步编程1.C#中async、await关键字2.编写异步方法3.异步方法并不等于多线程4.为什么有的异步方法没标async5.不要用sleep6.CancellationToken7.WhenAll8.异步编程中其他问题1.接口中的异......
  • ArgoWorkflow教程(八)---基于 LifecycleHook 实现流水线通知提醒
    本篇介绍一下ArgoWorkflow中的ExitHandler和LifecycleHook功能,可以根据流水线每一步的不同状态,执行不同操作,一般用于发送通知。1.概述本篇介绍一下ArgoWorkflow中的ExitHandler和LifecycleHook功能,可以根据流水线每一步的不同状态,执行不同操作,一般用于发送通知。......
  • IoC在ASP.NET Web API中的应用
    IoC在ASP.NETWebAPI中的应用 控制反转(InversionofControl,IoC),简单地说,就是应用本身不负责依赖对象的创建和维护,而交给一个外部容器来负责。这样控制权就由应用转移到了外部IoC容器,控制权就实现了所谓的反转。比如在类型A中需要使用类型B的实例,而B实例的创建并不由A来负责,......
  • HyperWorks的RT功能及使用技巧
    在Altair(HyperWorks)里,当结构中包含T型、X型或更复杂的连接特征(图2-12所示)时,此功能非常有效。不适用于没有T型连接的特征(图2-12右侧)。  图2-12带有T型特征的模型 如果R/T(半径/厚度)大于面板指定值,这个特征不被识别为目标连接特征。-如果某个连接特征的不同位......
  • Rethinking Network Design and Local Geometry in Point Cloud:A Simple Residual ML
    此内容是论文总结,重点看思路!!文章概述本文提出了一种用于点云分析的简单残差MLP网络(PointMLP),通过省略复杂的几何特征提取器,仅采用残差MLP和轻量化的几何仿射模块,便能高效地提取点云特征,实现优异的分类性能。PointMLP在推理速度和准确性上优于许多现有方法,提供了一种更加高效的......
  • UI组件DevExpress ASP.NET Bootstrap - 支持Bootstrap v5.3.3和暗黑模式
    在本文中,我们将详细介绍DevExpressBootstrap控件升级到Bootstrapv5.3.3、增强了DevExpressBootstrap项目模板的安全相关更新,以及对颜色模式的支持等。P.S.:DevExpress ASP.NETBootstrap Controls利用轻量级渲染、响应式布局和现代性能优化技术,扩展网站的受众范围并提高搜索......
  • Nginx 中动态调整 worker 进程绑定到特定 CPU 核心
    在Nginx中动态调整worker进程绑定到特定CPU核心,可以通过以下两种方式实现:###1.使用`auto`参数自动绑定Nginx1.9.10版本引入了`auto`参数,允许Nginx自动将worker进程绑定到可用的CPU上。这种方式不需要手动指定每个worker进程绑定到哪个CPU核心,Nginx会自......
  • asp.net程序设计2541教学网站的设计与实现
    项目包含:源码、论文、通用讲解视频、说明文档,部署录像开发环境开发工具:VisualStudio2010或以上版本数据库:SQLServer2005或以上版本开发语言:c#操作系统:windows7或以上浏览器:GoogleChrome(推荐)、Edge、360浏览器网络教学是随着计算机网络的蓬勃发展与广泛运用而......
  • VMwareWorkstation pro 17下载与安装
    1、安装包 VMwareWorkstationpro17:链接:https://pan.quark.cn/s/c75e892c4705提取码:YvyF2、安装教程1)       双击安装,弹窗安装对话框   2)       点击下一步 勾选我接受许可协议中的条款  3)       更改安装路径 4)安装到D......
  • framework配置文件读取
    写在 app.config 里面<?xmlversion="1.0"encoding="utf-8"?><configuration> <!--运行环境--><startup><supportedRuntimeversion="v4.0"sku=".NETFramework,Version=v4.7.2"/>......