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默认实现,内部封装了DbContextDbSet操作,适用于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属性)和DbContextawait 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
        };
    }
}

讲解:

  • 方法限制:仅包含GetAsyncGetListAsyncCountAsyncAverageAsync等查询方法,无任何写入操作,从接口层面避免误修改数据。
  • 适用场景:报表服务、数据导出、查询接口等纯读取场景,增强代码安全性和可读性。

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的DbContextDbSet,适合需要深度定制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的特性优势,是构建分层架构的核心工具。

posted @ 2025-10-24 20:47  【唐】三三  阅读(3)  评论(0)    收藏  举报