在.NET中实现仓储模式需定义泛型接口IRepository封装增删改查,用EF Core实现具体仓储类并配合工作单元(UnitOfWork)统一事务管理,提升解耦性、可测性及多数据源支持能力。

在.NET中实现仓储模式(Repository Pattern),核心是把数据访问逻辑从业务代码里抽离出来,用接口定义统一的数据操作契约,再由具体类去实现——这样既方便单元测试,又利于后期切换数据库或添加缓存层。
定义通用仓储接口
先写一个泛型接口 IRepository
- T 必须是 class(实体类)且有无参构造函数
- 方法签名尽量简洁,比如 GetByIdAsync、AddAsync、Update、Delete
- 支持异步操作(推荐),但同步方法可保留用于简单场景
- 可加 IQueryable
GetAll() 方便组合查询,但要小心过早执行(避免在仓储层调 .ToList())
基于Entity Framework Core实现仓储
新建 EFCoreRepository
- 构造函数接收 DbContext 和可选的 ILogger
- 所有异步方法内部调用 EF Core 的 async 版本(如 FindAsync、SaveChangesAsync)
- 更新操作建议用 Attach + EntityState.Modified 或先查再改(视并发需求而定)
- 删除慎用 RemoveRange,建议按ID批量处理并验证权限
配合工作单元(Unit of Work)提升一致性
单个仓储只管一类实体,多个仓储协作时容易出现事务不一致。引入 IUnitOfWork 接口封装 DbContext 的 SaveChanges:
- 接口包含各仓储的只读属性,如 IRepository
Users { get; } - 实现类持有 DbContext,并在 SaveChangesAsync() 中统一提交
- 注册到 DI 容器时,UnitOfWork 和所有仓储共用同一个 DbContext 实例(生命周期设为 Scoped)
在服务层中使用仓储
业务逻辑不再直接 new DbContext,而是通过构造函数注入 IUnitOfWork 或具体仓储接口:
- 例如用户注册服务:调用 _unitOfWork.Users.AddAsync(user),再 _unitOfWork.SaveChangesAsync()
- 查询时可用 _unitOfWork.Orders.GetAll().Where(x => x.Status == "Pending"),但更推荐在仓储中提供带条件的方法(如 GetByStatusAsync),保持职责清晰
- 单元测试时,用 Moq 模拟 IRepository
,完全隔离数据库
基本上就这些。不复杂但容易忽略的是:仓储不是万能的,别为了模式而堆砌;简单CRUD用 EF Core 自带的 DbSet 也完全OK;真正需要仓储,是当你开始关注解耦、可测性、多数据源或领域驱动设计(DDD)边界的时候。










