EF Core 使用流畅的扩展方法在范围服务中显式加载相关数据

EF Core explicitly loading related data in a scoped service using fluent extension methods

假设我有以下实体:

public class EntityA 
{
    //....
    public EntityB Child { get; set; }
}

public class EntityB
{
    //....
}

我有一个范围服务,我 return 这些实体:

public class MyScopedService
{
    public Task<IQueryable<EntityA>> GetById(int id)
    {
        var entity = _dbContext.EntityA.First(e => e.Id == id);
        return await Task.FromResult(entity);
    }
}

现在我想要一种显式加载相关数据的方法,就像这样:

public class MyScopedService
{
    public async Task<IQueryable<EntityA>> GetById(int id)
    {
        var entity = _dbContext.EntityA.First(e => e.Id == id);
        return await Task.FromResult(entity);
    }

    public static async Task<EntityA> WithEntityB(this EntityA entity)
    {
        return await _dbContext.Entry(entity).Reference(e => e.EntityB).LoadAsync();
    }
}

所以在页面或控制器或任何地方,我可以这样做:

var entity = await _myScopedService.GetById(id).WithEntityB();

显然,这不会起作用,因为您不能在非静态 class 中使用扩展方法。那么在范围服务内实现类似功能的最佳方式是什么?

我可以像这样将 DbContext 作为参数传递到扩展方法中:

var entity = await _myScopedService.GetById(id).WithEntityB(_myScopedService.DbContext);

但是我将不得不从我的作用域服务中公开我的上下文。我正在寻找不需要这个的东西。

您的方法毫无用处,尤其是在您关心性能的情况下。 您还可以做什么 - GetById return IQueryable

的正确方法
public class MyScopedService
{
    public IQueryable<EntityA> GetById(int id)
    {
        var query = _dbContext.EntityA.Where(e => e.Id == id);
        return query;
    }
}

WithEntityB - 这是 Include.

的奇怪替换
var entity = await _myScopedService.GetById(id).Include(e => e.EntityB).FirstAsync();

无论如何,你可以在WithEntityB和return中添加Include再次IQueryable

public static IQueryable<EntityA> WithEntityB(this IQueryable<EntityA> query)
{
    return query.Include(e => e.EntityB);
}
var entity = await _myScopedService.GetById(id).WithEntityB().FirstAsync();

你必须尽可能长时间地玩 IQueryable 的主要想法。最后,您必须使用一种可用的具体化方法(First、Single、ToArray、ToList、Count、Any 等)

此外,如果不需要,请不要创建异步方法。这是另一个性能差距。