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

C#中如何使用带Include与表达式的GenericRepository?

泛型仓储模式中GetAllIncludingAsync方法的Include参数调用问题

问题说明

已实现泛型仓储模式,定义了IGenericRepository接口及对应的GenericRepository实现类,但在调用GetAllIncludingAsync方法时,不清楚如何传入Include参数来关联查询Person实体。

现有代码

IGenericRepository接口

public interface IGenericRepository<T> where T : class
{
    Task<IEnumerable<T>> GetAllIncludingAsync(Expression<Func<T, bool>> expression, Expression<Func<object, bool>>[] includes, CancellationToken cancellationToken = default);
    Task<T?> GetIncludingAsync(Expression<Func<T, bool>> expression, Expression<Func<T, object>>[] includes, CancellationToken cancellationToken = default);
}

GenericRepository实现类

public class GenericRepository<T> : IGenericRepository<T> where T : class
{
    protected readonly MyDbContext _dbContext;
    private readonly DbSet<T> _entitySet;
    public GenericRepository(MyDbContext dbContext)
    {
        _dbContext = dbContext;
        _entitySet = _dbContext.Set<T>();
    }

    public async Task<IEnumerable<T>> GetAllIncludingAsync(Expression<Func<T, bool>> expression, Expression<Func<object, bool>>[] includes, CancellationToken cancellationToken = default)
    {
        IQueryable<T> query = _dbContext.Set<T>();
        foreach (var item in includes)
        {
            query = (IQueryable<T>)query.Include(item);
        }
        return await query.ToListAsync();
    }

    public async Task<T?> GetIncludingAsync(Expression<Func<T, bool>> expression, Expression<Func<T, object>>[] includes, CancellationToken cancellationToken = default)
    {
        IQueryable<T> query = _dbContext.Set<T>();
        foreach (var item in includes)
        {
            query = query.Include(item);
        }
        return await query.FirstOrDefaultAsync(expression);
    }
}

当前调用代码

IEnumerable<Booking>? bookings = await _unitOfWork
    .BookingRepository
    .GetAllIncludingAsync(x => x.Id == personId, y => y.Inc); //here I want to include Person

问题修正与正确调用方式

第一步:修正接口参数类型与实现缺陷

GetAllIncludingAsync方法的includes参数类型定义错误,需和GetIncludingAsync保持一致,改为Expression<Func<T, object>>[],否则会引发类型转换异常。同时原实现遗漏了过滤条件的应用,需补充Where逻辑:

修正后的接口方法

Task<IEnumerable<T>> GetAllIncludingAsync(Expression<Func<T, bool>> expression, Expression<Func<T, object>>[] includes, CancellationToken cancellationToken = default);

修正后的实现类方法

public async Task<IEnumerable<T>> GetAllIncludingAsync(Expression<Func<T, bool>> expression, Expression<Func<T, object>>[] includes, CancellationToken cancellationToken = default)
{
    IQueryable<T> query = _dbContext.Set<T>();
    foreach (var item in includes)
    {
        query = query.Include(item);
    }
    // 应用传入的过滤条件
    query = query.Where(expression);
    return await query.ToListAsync(cancellationToken);
}

第二步:正确传入Include参数

假设Booking实体包含名为Person的导航属性,调用时传入表示该导航属性的表达式数组即可:

// 关联单个导航属性的情况
IEnumerable<Booking>? bookings = await _unitOfWork
    .BookingRepository
    .GetAllIncludingAsync(
        x => x.Id == personId, 
        new[] { x => x.Person }, // 指定要关联的Person导航属性
        CancellationToken.None);

如果需要同时关联多个导航属性,直接在数组中添加对应表达式:

// 关联多个导航属性的情况
IEnumerable<Booking>? bookings = await _unitOfWork
    .BookingRepository
    .GetAllIncludingAsync(
        x => x.Id == personId, 
        new[] { x => x.Person, x => x.Room }, // 同时关联Person和Room
        CancellationToken.None);

额外优化建议

  • 给includes参数设置默认值null,无需关联查询时可省略该参数:
    Task<IEnumerable<T>> GetAllIncludingAsync(Expression<Func<T, bool>> expression, Expression<Func<T, object>>[]? includes = null, CancellationToken cancellationToken = default);
    
    实现类中需增加空值判断:
    if (includes != null)
    {
        foreach (var item in includes)
        {
            query = query.Include(item);
        }
    }
    
  • 若需要支持多层级导航属性(如Booking.Person.Addresses),可扩展方法支持ThenInclude逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 16:20:22