C#怎么实现仓储模式 Repository Pattern在.NET中的实践

13次阅读

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

C#怎么实现仓储模式 Repository Pattern在.NET中的实践

在.NET中实现仓储模式(Repository Pattern),核心是把数据访问逻辑从业务代码里抽离出来,用接口定义统一的数据操作契约,再由具体类去实现——这样既方便单元测试,又利于后期切换数据库或添加缓存层。

定义通用仓储接口

先写一个泛型接口 IRepository,覆盖增删改查基本操作。注意它不依赖具体ORM,也不暴露DbContext或DbSet细节:

  • T 必须是 class(实体类)且有无参构造函数
  • 方法签名尽量简洁,比如 GetByIdAsyncAddAsyncUpdatedelete
  • 支持异步操作(推荐),但同步方法可保留用于简单场景
  • 可加 IQueryable GetAll() 方便组合查询,但要小心过早执行(避免在仓储层调 .ToList())

基于Entity Framework Core实现仓储

新建 EFCoreRepository 类,注入 DbContext,通过 Set() 获取 DbSet。关键点:

  • 构造函数接收 DbContext 和可选的 ILogger
  • 所有异步方法内部调用 EF Core 的 async 版本(如 FindAsyncSaveChangesAsync
  • 更新操作建议用 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)边界的时候。

text=ZqhQzanResources