ABP - 仓储(Repository)[IRepository、EfCoreRepository、SqlSugarRepository、IReadOnlyRepository、EfCoreRepositoryBase]
仓储(Repository)
核心辅助类:
IRepository<TEntity, TKey>:通用仓储接口(CRUD操作)。EfCoreRepository<TEntity, TKey>:EF Core实现(默认)。SqlSugarRepository<TEntity, TKey>:SqlSugar实现。IReadOnlyRepository<TEntity, TKey>:只读仓储接口(仅包含查询方法,适用于不需要修改数据的场景)。EfCoreRepositoryBase<TDbContext, TEntity, TKey>:EF Core 仓储基类,可自定义数据库上下文。
在ABP框架中,仓储(Repository)是数据访问层的核心抽象,用于隔离业务逻辑与数据访问细节。以下是仓储相关接口和实现类的具体示例及讲解,涵盖EF Core和SqlSugar两种ORM场景:
1. IRepository<TEntity, TKey>:通用仓储接口(核心CRUD)
IRepository<TEntity, TKey>是ABP定义的通用仓储接口,封装了实体的完整CRUD操作(查询、新增、更新、删除),是所有仓储实现的基础接口,不依赖具体ORM。
示例:使用IRepository接口
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Application.Services;
// 实体(领域层)
public class Product : Entity<Guid>
{
public string Name { get; set; }
public decimal Price { get; set; }
}
// 应用服务(依赖IRepository)
public class ProductAppService : ApplicationService
{
// 注入通用仓储接口(不关心底层ORM)
private readonly IRepository<Product, Guid> _productRepository;
public ProductAppService(IRepository<Product, Guid> productRepository)
{
_productRepository = productRepository;
}
// 新增
public async Task<Product> CreateAsync(Product input)
{
return await _productRepository.InsertAsync(input);
}
// 按条件查询
public async Task<List<Product>> GetCheaperProductsAsync(decimal maxPrice)
{
return await _productRepository.GetListAsync(p => p.Price <= maxPrice);
}
// 分页查询
public async Task<long> GetTotalCountAsync()
{
return await _productRepository.CountAsync();
}
}
讲解:
- 核心方法:包含
InsertAsync(新增)、GetAsync(单查)、GetListAsync(列表查询)、UpdateAsync(更新)、DeleteAsync(删除)、CountAsync(计数)等,覆盖所有基础数据操作。 - ORM无关性:接口定义与具体ORM(EF Core/SqlSugar)无关,业务层无需修改代码即可切换ORM。
- 依赖注入:ABP会自动根据项目配置的ORM注册对应的实现类(如EF Core项目注册
EfCoreRepository),业务层直接注入IRepository即可使用。
2. EfCoreRepository<TEntity, TKey>:EF Core默认实现
EfCoreRepository<TEntity, TKey>是ABP为EF Core提供的IRepository默认实现,内部封装了DbContext和DbSet操作,适用于EF Core作为ORM的项目。
示例:使用EF Core仓储
using Volo.Abp.EntityFrameworkCore.Repositories;
using Microsoft.EntityFrameworkCore;
// 1. 定义EF Core数据库上下文
public class MyAppDbContext : AbpDbContext<MyAppDbContext>
{
// 注册实体DbSet
public DbSet<Product> Products { get; set; }
public MyAppDbContext(DbContextOptions<MyAppDbContext> options) : base(options)
{
}
}
// 2. 自定义EF Core仓储(继承EfCoreRepository)
public class ProductEfCoreRepository : EfCoreRepository<MyAppDbContext, Product, Guid>, IProductRepository
{
// 注入数据库上下文(父类已处理,可直接使用)
public ProductEfCoreRepository(IDbContextProvider<MyAppDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
// 扩展自定义查询(使用EF Core的Include关联查询)
public async Task<Product> GetWithCategoryAsync(Guid id)
{
// 访问EF Core的DbSet,使用Include关联查询
return await DbSet
.Include(p => p.Category) // 关联查询分类
.FirstOrDefaultAsync(p => p.Id == id);
}
}
// 3. 仓储接口(继承IRepository)
public interface IProductRepository : IRepository<Product, Guid>
{
Task<Product> GetWithCategoryAsync(Guid id); // 自定义方法
}
讲解:
- 基础实现:继承
EfCoreRepository后,自动获得IRepository的所有方法实现,无需重复编写。 - EF Core特性:可直接访问
DbSet(仓储内的DbSet属性)和DbContext(await GetDbContextAsync()),使用EF Core的关联查询(Include)、跟踪机制等特性。 - 数据库上下文绑定:通过泛型参数
MyAppDbContext指定当前仓储使用的数据库上下文,支持多上下文场景。
3. SqlSugarRepository<TEntity, TKey>:SqlSugar实现
SqlSugarRepository<TEntity, TKey>是社区为SqlSugar ORM提供的仓储实现,适配ABP的IRepository接口,保留SqlSugar的链式查询优势。
示例:使用SqlSugar仓储
using SqlSugar;
using Volo.Abp.Domain.Repositories;
// 1. 自定义SqlSugar仓储(继承SqlSugarRepository)
public class ProductSqlSugarRepository : SqlSugarRepository<Product, Guid>, IProductRepository
{
// 注入SqlSugar客户端(父类已封装)
public ProductSqlSugarRepository(ISqlSugarClient sqlSugarClient)
: base(sqlSugarClient)
{
}
// 扩展自定义查询(使用SqlSugar的链式查询)
public async Task<Product> GetWithCategoryAsync(Guid id)
{
// 使用SqlSugar的Queryable和Include语法
return await DbClient.Queryable<Product>()
.Include(p => p.Category) // 关联查询
.Where(p => p.Id == id)
.FirstAsync();
}
}
// 2. 复用IProductRepository接口(与EF Core版本一致)
public interface IProductRepository : IRepository<Product, Guid>
{
Task<Product> GetWithCategoryAsync(Guid id);
}
讲解:
- SqlSugar特性:内部通过
ISqlSugarClient实现操作,支持SqlSugar的链式查询(Queryable)、Lambda条件、高性能批量操作等。 - 接口兼容:与EF Core仓储实现同一接口(
IProductRepository),业务层切换ORM时无需修改服务代码,只需替换仓储实现。
4. IReadOnlyRepository<TEntity, TKey>:只读仓储接口
IReadOnlyRepository<TEntity, TKey>是IRepository的子集,仅包含查询相关方法(无Insert/Update/Delete),适用于只需要读取数据的场景(如报表服务、查询服务)。
示例:使用只读仓储
using Volo.Abp.Domain.Repositories;
// 只读服务(仅需查询数据)
public class ProductReportAppService : ApplicationService
{
// 注入只读仓储(限制写入操作)
private readonly IReadOnlyRepository<Product, Guid> _productRepository;
public ProductReportAppService(IReadOnlyRepository<Product, Guid> productRepository)
{
_productRepository = productRepository;
}
// 生成价格统计报表(仅查询)
public async Task<PriceReportDto> GeneratePriceReportAsync()
{
var totalCount = await _productRepository.CountAsync();
var avgPrice = await _productRepository.AverageAsync(p => p.Price);
var maxPrice = await _productRepository.MaxAsync(p => p.Price);
return new PriceReportDto
{
TotalCount = totalCount,
AveragePrice = avgPrice,
MaxPrice = maxPrice
};
}
}
讲解:
- 方法限制:仅包含
GetAsync、GetListAsync、CountAsync、AverageAsync等查询方法,无任何写入操作,从接口层面避免误修改数据。 - 适用场景:报表服务、数据导出、查询接口等纯读取场景,增强代码安全性和可读性。
5. EfCoreRepositoryBase<TDbContext, TEntity, TKey>:EF Core自定义上下文基类
EfCoreRepositoryBase是EF Core仓储的底层基类,允许直接指定数据库上下文类型,适用于多数据库上下文场景(如一个项目连接多个数据库)。
示例:多上下文场景下使用EfCoreRepositoryBase
using Volo.Abp.EntityFrameworkCore.Repositories;
using Microsoft.EntityFrameworkCore;
// 1. 定义两个数据库上下文(如主库和日志库)
public class MainDbContext : AbpDbContext<MainDbContext>
{
public DbSet<Product> Products { get; set; } // 主库实体
// 构造函数...
}
public class LogDbContext : AbpDbContext<LogDbContext>
{
public DbSet<OperationLog> OperationLogs { get; set; } // 日志实体
// 构造函数...
}
// 2. 主库仓储(绑定MainDbContext)
public class ProductRepository : EfCoreRepositoryBase<MainDbContext, Product, Guid>, IProductRepository
{
public ProductRepository(IDbContextProvider<MainDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
}
// 3. 日志仓储(绑定LogDbContext)
public class OperationLogRepository : EfCoreRepositoryBase<LogDbContext, OperationLog, Guid>, IOperationLogRepository
{
public OperationLogRepository(IDbContextProvider<LogDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
}
讲解:
- 多上下文支持:通过泛型参数
TDbContext明确指定仓储绑定的数据库上下文,解决多库场景下的实体隔离问题。 - 底层控制:继承自
EfCoreRepositoryBase可直接访问EF Core的DbContext和DbSet,适合需要深度定制EF Core操作的场景。
总结:仓储组件的选择与设计
| 组件 | 核心作用 | 适用场景 |
|---|---|---|
IRepository<TEntity, TKey> |
定义通用CRUD接口 | 业务层依赖注入,不关心ORM实现 |
EfCoreRepository<TEntity, TKey> |
EF Core的默认实现 | EF Core项目,单数据库上下文 |
SqlSugarRepository<TEntity, TKey> |
SqlSugar的实现 | SqlSugar项目,需要高效链式查询 |
IReadOnlyRepository<TEntity, TKey> |
只读查询接口 | 纯查询场景(报表、导出),避免数据修改 |
EfCoreRepositoryBase<...> |
EF Core多上下文基类 | 多数据库上下文场景,需明确绑定上下文 |
ABP的仓储设计遵循“接口抽象+ORM实现”的模式,既保证了业务层与数据访问层的解耦,又保留了不同ORM的特性优势,是构建分层架构的核心工具。

浙公网安备 33010602011771号