我正在寻找一种有效地生成和重用Entity Framework Core中(相当大的)查询的一部分的方法。
我的目标如下:
我当前的查询看起来像这样(简化的)示例:
var itemDetailsQuery = getQueryable(x => x.Id == itemId);
var item = await itemDetailsQuery.FirstOrDefaultAsync();
private IQueryable<Item> getQueryable(Expression<Func<Item,bool>> predicate)
{
return _itemRepository
.GetAll()
.Where(predicate)
.Include(x => x.ItemChildren)
.ThenInclude(x => x.ItemGrandChildren)
.ThenInclude(x => x.ItemGreatGrandChildren1)
.Include(x => x.ItemChildren)
.ThenInclude(x => x.ItemGrandChildren)
.ThenInclude(x => x.ItemGreatGrandChildren2)
.Include(x => x.ItemChildren)
.ThenInclude(x => x.ItemGrandChildren)
.ThenInclude(x => x.ItemGreatGrandChildren3)
.ThenInclude(x => x.ItemGreatGreatGrandChildren)
.ThenInclude(x => x.ItemGreatGreatGreatGrandChildren);
}
以上方法有效,但:
我发现下面的帖子非常有趣,建议使用表达式和投影来实现所需的结果,这很整洁,因为我可以在每个类中将表达式用作投影:
https://benjii.me/2018/01/expression-projection-magic-entity-framework-core/
我对此的实现如下,每个子类都有自己的投影,因此使用此策略可以将多个级别链接在一起(请注意,ToList()是必需的,因为我的集合属性是ICollections而不是IEnumerables;尽管我担心这可能会导致过早执行:
private IQueryable<Item> getQueryable(Expression<Func<Item,bool>> predicate)
{
return _itemRepository
.GetAll()
.AsExpandable()
.Where(predicate)
.Select(x => new Item
{
Id = x.Id,
Name = x.Name,
ItemChildren = x.ItemChildren.AsQueryable().Select(ItemChild.Projection).ToList(),
});
}
但是,当我尝试此操作时,经过第二层子级后,什么也没有加载;可能不是设计成多层嵌套使用链式方式。
我已经研究了包括扩展方法在内的替代策略,但是尽管我可以用它们替代第一层的Includes,但是我找不到一种方法来替代这些方法,因此我可以执行以下操作:
private IQueryable<Item> getQueryable(Expression<Func<Item,bool>> predicate)
{
return _itemRepository
.GetAll()
.Where(predicate)
.Include(x => x.ItemChildren)
.IncludeGrandChildren();
}
private IIncludableQueryable<ItemGrandChildren, ItemGreatGrandChildren3> IncludeGrandChildren(this IQueryable<ItemGrandChildren> values)
{
return values
.Include(x => x.ItemGreatGrandChildren1)
.Include(x => x.ItemGreatGrandChildren2)
.Include(x => x.ItemGreatGrandChildren3)
.ThenInclude(x => x.ItemGreatGreatGrandChildren)
.ThenInclude(x => x.ItemGreatGreatGreatGrandChildren);
}
我感觉到我缺少或误解了一些基本知识,但是任何建议都将不胜感激。