在构建.NET应用时,数据访问层设计常引发架构争议:该直接使用Entity Framework,还是引入Repository模式或Repository+工作单元组合? 本文将深度解析三种方案的优缺点,助你做出明智选择。
核心思想:直接通过DbContext
操作数据,无需额外抽象层
代码示例:
// 1. 定义实体模型
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
}
// 2. 创建DbContext
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Product> Products { get; set; }
}
// 3. 配置并注册服务
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlite("Data Source=app.db"));
// 4. 在Minimal API中直接使用DbContext
app.MapGet("/products", async (AppDbContext db) => await db.Products.ToListAsync());
✅ 优势:
GetById()
等基础方法IQueryable
、LINQ、延迟加载等高级特性❌ 劣势:
核心思想:通过接口封装数据访问,实现解耦
代码示例:
// 1. 定义Repository接口
public interface IProductRepository
{
Task<IEnumerable<Product>> GetAllAsync();
Task<Product?> GetByIdAsync(int id);
Task AddAsync(Product product);
// 其他方法...
}
// 2. 实现Repository
public class ProductRepository : IProductRepository
{
private readonly AppDbContext _context;
public ProductRepository(AppDbContext context) => _context = context;
public async Task<IEnumerable<Product>> GetAllAsync() =>
await _context.Products.ToListAsync();
}
// 3. 注册服务
builder.Services.AddScoped<IProductRepository, ProductRepository>();
// 4. API注入Repository
app.MapGet("/products", async (IProductRepository repo) => await repo.GetAllAsync());
✅ 优势:
❌ 劣势:
核心思想:通过工作单元管理事务性操作
代码示例:
// 1. 定义工作单元接口
public interface IUnitOfWork : IDisposable
{
IProductRepository Products { get; }
Task<int> SaveChangesAsync();
}
// 2. 实现工作单元
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public IProductRepository Products { get; }
public UnitOfWork(AppDbContext context, IProductRepository repo)
{
_context = context;
Products = repo;
}
public async Task<int> SaveChangesAsync() => await _context.SaveChangesAsync();
}
// 3. API中使用工作单元
app.MapPost("/products", async (IUnitOfWork uow, Product product) =>
{
await uow.Products.AddAsync(product);
await uow.SaveChangesAsync(); // 事务提交
return Results.Created($"/products/{product.Id}", product);
});
✅ 优势:
❌ 劣势:
DbContext
已内置工作单元| 方案 | 适用场景 | 不适用场景 |
|-------------------------|---------------------------------------|---------------------------|
| 直接使用EF | 小型项目,快速开发,无需切换ORM | 需要解耦测试或多数据库支持 |
| Repository模式 | 中大型项目,需隔离数据层,便于测试 | 简单CRUD,无需抽象 |
| Repository+工作单元 | 复杂事务,多仓储协调,高一致性要求 | 小型应用,单表操作 |
小型项目可直击EF核心优势,中大型系统通过Repository模式换取灵活性与可测性,复杂事务场景则需工作单元加持。决策时需权衡项目规模、团队习惯与长期维护成本,警惕过度设计。