在 ASP.NET Core 中使用 Entity Framework Core 实现一个带有事务的工作单元(Unit of Work)模式的仓储层和服务层,可以确保在执行多个数据库操作时具有原子性。这样,即使某个操作出现错误,所有操作也可以回滚。
以下是如何实现这个模式的详细步骤:
- 定义实体类
我们首先定义一个简单的实体类,例如 Product:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
- 定义数据库上下文
定义一个继承自 DbContext 的数据上下文类:
public class ApplicationDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
}
- 定义仓储接口和实现
创建一个通用的仓储接口并实现它:
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();
}
- 定义工作单元接口和实现,支持事务
在工作单元实现中,我们将包含事务处理。可以使用 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();
}
}
- 创建服务层
服务层使用工作单元和仓储,确保在需要时可以开启和提交事务:
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;
}
}
- 在 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>();
}
- 使用服务层
最后,创建一个控制器来使用服务层:
[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