You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何跨DbSet复用EF Core查询表达式?

通用化EF Core中继承基类的DbSet查询逻辑

方案一:泛型基服务类实现

定义泛型基服务类,约束泛型参数为JobWithHistoryBase的派生类,将通用查询逻辑封装在基类中:

public abstract class JobHistoryServiceBase<TJob> where TJob : JobWithHistoryBase
{
    private readonly IDbContextFactory<YourDbContext> _contextFactory;

    protected JobHistoryServiceBase(IDbContextFactory<YourDbContext> contextFactory)
    {
        _contextFactory = contextFactory;
    }

    public async Task<List<JobHistoryDto>> GetHistoryForWorkflow(int workflowId)
    {
        using var context = _contextFactory.CreateDbContext();
        var dbSet = context.Set<TJob>();
        
        return await dbSet
            .AsNoTracking()
            .Where(x => x.WorkflowId == workflowId)
            .Select(x => new JobHistoryDto()
            {
                WorkflowId = x.WorkflowId,
                ActivityLabel = x.Activity.Label,
                ActivityByPersonUserName = x.ActivityByPerson.Username,
                ActivityStartDate = x.ActivityStartDate,
                Comment = x.Comment
            })
            .ToListAsync();
    }
}

让具体服务类继承该基类,指定对应泛型参数即可复用逻辑:

public class MeterInstallService : JobHistoryServiceBase<MeterInstallJob>
{
    public MeterInstallService(IDbContextFactory<YourDbContext> contextFactory) 
        : base(contextFactory)
    {
    }

    // 可在此添加专属业务方法
}

public class MeterRepairService : JobHistoryServiceBase<MeterRepairJob>
{
    public MeterRepairService(IDbContextFactory<YourDbContext> contextFactory) 
        : base(contextFactory)
    {
    }

    // 可在此添加专属业务方法
}

方案二:基于IQueryable的通用扩展方法

若不想修改服务类继承结构,可封装静态扩展方法,接收IQueryable<JobWithHistoryBase>作为输入:

public static class JobHistoryQueryHelper
{
    public static async Task<List<JobHistoryDto>> GetHistoryForWorkflowAsync(
        this IQueryable<JobWithHistoryBase> queryable, 
        int workflowId)
    {
        return await queryable
            .AsNoTracking()
            .Where(x => x.WorkflowId == workflowId)
            .Select(x => new JobHistoryDto()
            {
                WorkflowId = x.WorkflowId,
                ActivityLabel = x.Activity.Label,
                ActivityByPersonUserName = x.ActivityByPerson.Username,
                ActivityStartDate = x.ActivityStartDate,
                Comment = x.Comment
            })
            .ToListAsync();
    }
}

在具体服务类中直接调用该扩展方法:

public class MeterInstallService
{
    private readonly IDbContextFactory<YourDbContext> _contextFactory;

    public MeterInstallService(IDbContextFactory<YourDbContext> contextFactory)
    {
        _contextFactory = contextFactory;
    }

    public async Task<List<JobHistoryDto>> GetHistoryForWorkflow(int workflowId)
    {
        using var context = _contextFactory.CreateDbContext();
        return await context.MeterInstallJob.GetHistoryForWorkflowAsync(workflowId);
    }
}

public class MeterRepairService
{
    private readonly IDbContextFactory<YourDbContext> _contextFactory;

    public MeterRepairService(IDbContextFactory<YourDbContext> contextFactory)
    {
        _contextFactory = contextFactory;
    }

    public async Task<List<JobHistoryDto>> GetHistoryForWorkflow(int workflowId)
    {
        using var context = _contextFactory.CreateDbContext();
        return await context.MeterRepairJob.GetHistoryForWorkflowAsync(workflowId);
    }
}

关键说明

  • 泛型基类方案适合服务类结构统一的场景,后续新增同类型服务只需继承基类即可,重复代码最少。
  • IQueryable扩展方法方案更灵活,无需调整已有服务类的继承关系,适配性更强。
  • 两种方案均利用EF Core的泛型Set<T>()方法或DbSet自动转换为IQueryable的特性,确保查询针对目标派生类的DbSet正确执行。

内容的提问来源于stack exchange,提问作者Wes H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:42:49