C# 架构精通 — EF Core 在 Clean Architecture 中 (第8部分)
发布: (2025年12月24日 GMT+8 05:01)
4 分钟阅读
原文: Dev.to
Source: Dev.to
EF Core 在 Clean Architecture 中的角色
-
EF Core 是什么
- 持久化机制
- 数据映射工具
- 基础设施关注点
-
EF Core 不是
- 领域模型
- 业务规则引擎
- 架构基础
如果 EF Core 向内泄漏,Clean Architecture 将崩溃。
EF Core 所在位置
Infrastructure
└─ Persistence
├─ DbContext
├─ EntityConfigurations
└─ Repositories
Domain 和 Application 层绝不能引用:
DbContextDbSet- EF Core 特性
- EF Core LINQ 扩展
硬性边界:不允许 DbContext 泄漏
// ❌ DbContext leaking inward
class CreateOrderUseCase
{
private readonly AppDbContext _db;
}
后果
- 紧耦合
- 持久化感知的业务逻辑
- 用例不可测试
依赖接口,而非 EF Core
public interface IOrderRepository
{
Task SaveAsync(Order order);
Task GetByIdAsync(OrderId id);
}
基础设施实现
class EfOrderRepository : IOrderRepository
{
private readonly AppDbContext _db;
public async Task SaveAsync(Order order)
{
_db.Orders.Add(order);
await _db.SaveChangesAsync();
}
}
EF Core 通过仓库抽象保持隔离。
高级指南:让领域驱动 EF Core
-
避免
- 为 EF 设计的贫血实体
- 到处使用公共 setter
- 持久化驱动的不变量
-
倾向
- 丰富的领域模型
- 封装
- 明确的不变量
EF Core 能映射私有字段和构造函数。
常见错误:IQueryable 向上泄漏
// ❌ IQueryable leaking upward
IQueryable Orders { get; }
为什么危险
- 将逻辑耦合到 EF 查询翻译
- 破坏抽象层
- 将业务规则推入查询中
正确做法
- 将 LINQ 保持在仓库内部
- 返回领域对象或 DTO
EF Core 不适用的场景
- 复杂的报表查询
- 高性能读取模型
- 批量操作
- 大量分析
高级团队通常会组合使用:
- EF Core 负责写入和聚合
- Dapper / 原始 SQL 负责读取
这种混合方式是完全可接受的。
EF Core 擅长的事务
- 迁移
- 更改跟踪
- 事务
工作单元(Unit of Work) 概念属于应用层:
public interface IUnitOfWork
{
Task CommitAsync();
}
EF Core 提供实现,但不定义抽象。
测试指南
- 要做:使用真实提供程序编写集成测试;验证映射和约束。
- 避免:为逻辑测试模拟
DbContext或过度使用 InMemory 提供程序。
如果 EF Core 难以测试,说明边界可能放错了位置。
警示信号(边界违规)
DbContext注入到控制器或领域服务中- 在领域实体上使用 EF 特性
- 在 LINQ 查询中嵌入业务规则
- 过度依赖惰性加载
每一种味道都表明架构边界被突破。
总结
- 正确用法:EF Core 隐藏在抽象后面,支持领域,并且可以被替换。
- 错误用法:EF Core 成为系统本身,支配设计,阻碍演进。
在 Clean Architecture 中,EF Core 必须服务领域——绝不能统治领域。
作者:Cristian Sifuentes — 帮助团队驯服 EF Core,使架构保持清晰、可测试且具弹性。