在现代 .NET 开发中,确保关注点分离、干净的代码和高效的数据处理至关重要。Unit of Work 和 Repository 模式被广泛用于简化数据访问,而依赖注入 (DI) 已成为提高性能和可扩展性的标准实践。在本文中,我将展示如何有效地实现这些模式。
Repository Pattern 抽象了数据访问层,提供了一种与数据库交互的方法,而不会暴露底层数据库操作的复杂性。
我们将定义一个基本接口,该接口可以处理任何实体的基本 CRUD 操作:IRepository<T>
public interface IRepository<T> where T : class
{
Task<List<T>> GetAllAsync();
Task<T> GetByIdAsync(int id);
Task AddAsync(T entity);
void Update(T entity);
void Delete(T entity);
}
接下来,我们实现 class:Repository<T>
public class Repository<T> : IRepository<T> where T : class
{
protected readonly DbContext _context;
protected readonly DbSet<T> _dbSet;
public Repository(DbContext context)
{
_context = context;
_dbSet = _context.Set<T>();
}
public async Task<List<T>> GetAllAsync()
{
return await _dbSet.ToListAsync();
}
public async Task<T> GetByIdAsync(int id)
{
return await _dbSet.FindAsync(id);
}
public async Task AddAsync(T entity)
{
await _dbSet.AddAsync(entity);
}
public void Update(T entity)
{
_dbSet.Update(entity);
}
public void Delete(T entity)
{
_dbSet.Remove(entity);
}
}
在这里,异步方法确保数据库操作不会阻塞主线程,从而提高性能和可扩展性。
对于更复杂的实体,例如 ,我们可能需要基本 CRUD 操作之外的其他方法。例如,检索用户及其关联的订单:User
// User Repository
public interface IUserRepository : IRepository<User>
{
Task<User> GetUserWithOrdersAsync(int id);
}
public class UserRepository : Repository<User>, IUserRepository
{
public UserRepository(DbContext context) : base(context) { }
public async Task<User> GetUserWithOrdersAsync(int id)
{
return await _context.Set<User>()
.Include(u => u.Orders)
.FirstOrDefaultAsync(u => u.Id == id);
}
}
// Order Repository
public interface IOrderRepository : IRepository<Order>
{
Task<List<Order>> GetOrdersByUserIdAsync(int userId);
}
public class OrderRepository : Repository<Order>, IOrderRepository
{
public OrderRepository(DbContext context) : base(context) { }
public async Task<List<Order>> GetOrdersByUserIdAsync(int userId)
{
return await _dbSet.Where(o => o.UserId == userId).ToListAsync();
}
}
Unit of Work 模式确保特定业务事务中的所有操作都作为一个操作提交或回滚。我们使用依赖注入 (DI) 将存储库注入到类中,从而使我们能够集中事务管理。UnitOfWork
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly DbContext _context;
private readonly IServiceProvider _serviceProvider;
private bool _disposed = false;
public UnitOfWork(DbContext context, IServiceProvider serviceProvider)
{
_context = context;
_serviceProvider = serviceProvider;
}
public IUserRepository UserRepository => _serviceProvider.GetService<IUserRepository>();
public IOrderRepository OrderRepository => _serviceProvider.GetService<IOrderRepository>();
public async Task<int> CompleteAsync()
{
return await _context.SaveChangesAsync();
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
在此 中,我们用于异步保存所有更改。存储库通过 Lazilyly 解析,以确保它们仅在必要时被实例化。UnitOfWorkCompleteAsync()IServiceProvider
在现代应用程序中,DTO (数据传输对象) 通常用于在客户端和服务器之间传输数据。控制器不应直接与实体打交道,而应依赖 DTO 来确保数据模型和 API 协定之间的明确分离。
public class UserDto
{
public string Name { get; set; }
public string Email { get; set; }
}
public class OrderDto
{
public string ProductName { get; set; }
public decimal Price { get; set; }
}
public class CreateUserWithOrderDto
{
public UserDto User { get; set; }
public OrderDto Order { get; set; }
}
DTO 抽象了基础实体的详细信息,从而允许在客户端和服务器之间实现更安全、更清晰的通信。
服务层包含应用程序的业务逻辑,保证控制器只协调数据流。以下是我们构建 :UserService
public class UserService
{
private readonly IUnitOfWork _unitOfWork;
public UserService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public async Task<UserDto> GetUserByIdAsync(int id)
{
var user = await _unitOfWork.UserRepository.GetUserWithOrdersAsync(id);
if (user == null) return null;
return new UserDto { Name = user.Name, Email = user.Email };
}
public async Task CreateUserAndOrderAsync(UserDto userDto, OrderDto orderDto)
{
// Create a User
var user = new User { Name = userDto.Name, Email = userDto.Email };
await _unitOfWork.UserRepository.AddAsync(user);
// Create an Order tied to the user
var order = new Order { ProductName = orderDto.ProductName, Price = orderDto.Price, UserId = user.Id };
await _unitOfWork.OrderRepository.AddAsync(order);
// Save both User and Order in a single transaction
await _unitOfWork.CompleteAsync();
}
public async Task DeleteUserAndOrdersAsync(int userId)
{
// Find the user
var user = await _unitOfWork.UserRepository.GetByIdAsync(userId);
if (user != null)
{
// Find and delete user's orders
var orders = await _unitOfWork.OrderRepository.GetOrdersByUserIdAsync(userId);
foreach (var order in orders)
{
_unitOfWork.OrderRepository.Delete(order);
}
// Delete the user after orders are deleted
_unitOfWork.UserRepository.Delete(user);
// Save both User and Order deletions in a single transaction
await _unitOfWork.CompleteAsync();
}
}
}
要完成设置,我们需要在 DI 容器中注册 repositories、 和 service 类:UnitOfWork
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// Register repositories and UnitOfWork
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IOrderRepository, OrderRepository>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
// Register services
services.AddScoped<UserService>();
}
通过此配置,我们确保 and 存储库被注入到需要的地方。UnitOfWork
控制器专注于处理 HTTP 请求和响应,将所有业务逻辑委托给服务层。以下是设置 :UsersController
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly UserService _userService;
public UsersController(UserService userService)
{
_userService = userService;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetUserAsync(int id)
{
var user = await _userService.GetUserByIdAsync(id);
if (user == null) return NotFound();
return Ok(user);
}
[HttpPost]
public async Task<IActionResult> CreateUserWithOrderAsync([FromBody] CreateUserWithOrderDto createUserWithOrderDto)
{
await _userService.CreateUserAndOrderAsync(createUserWithOrderDto.User, createUserWithOrderDto.Order);
return CreatedAtAction(nameof(GetUserAsync), new { id = createUserWithOrderDto.User.Name }, createUserWithOrderDto.User);
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteUserAndOrdersAsync(int id)
{
await _userService.DeleteUserAndOrdersAsync(id);
return NoContent();
}
}
Unit of Work 和 Repository 模式是用于在 C# 应用程序中维护事务一致性和关注点分离的强大工具。当与 Dependency Injection 结合使用时,您将获得一个干净、可扩展的架构,该架构既可维护又高性能。