使用Automapper优化相关子查询

别裁伪体亲风雅,转益多师是汝师。这篇文章主要讲述使用Automapper优化相关子查询相关的知识,希望能为你提供帮助。
更新:Automapper在简单的情况下自动应用它,因为它already adds a ToList()。我看到的这个问题导致我打开这个问题变成了一个更复杂的问题(SoftwareIds member是N+1的罪魁祸首。见this。)。
在EF Core 2.1中,我们获得了在LINQ子查询上添加ToList()以缓冲结果并避免N + 1数据库查询的支持。 (Docs)这对于针对DbContext的简单LINQ查询非常有用。
但是,如果我有一个Automapper配置文件导致N + 1个查询:

public MyMappingProfile() => CreateMap< MyEntity, MyDto> ().ForMember(e => e.MyCollectionProp, o => o.MapFrom(l => l.MyCollectionPropMany.Select(la => la.MyCollectionEntity)))

添加ToList()会抛出异常:
public MyMappingProfile() => CreateMap< MyEntity, MyDto> ().ForMember(e => e.MyCollectionProp, o => o.MapFrom(l => l.MyCollectionPropMany.Select(la => la.MyCollectionEntity).ToList()))

System.NotSupportedException:'无法解析表达式'MyDto.MyCollectionPropMany.Select(la => la.MyCollectionEntity).ToList()':当前不支持方法'System.Linq.Enumerable.ToList'的重载。
有没有办法在Automapper配置文件中启用子查询缓冲?
楷模:
public class MyEntity { public int Id { get; set; } public ICollection< MyCollectionPropMany> MyCollectionPropManys { get; set; } ... }public class MyCollectionPropMany { public int MyEntityId { get; set; } public MyEntity MyEntity { get; set; } public int MyCollectionPropId { get; set; } public MyCollectionProp MyCollectionProp { get; set; } }public class MyCollectionProp { public int Id { get; set; } public ICollection< MyCollectionPropMany> MyCollectionPropManys { get; set; } ... }public class MyDto { public int Id { get; set; } public IEnumerable< MyCollectionPropDto> MyCollectionPropDtos { get; set; } ... }public class MyCollectionPropDto { public string Name { get; set; } ... }

Automapper v7.0.1
真实场景(我试图简化/制作SO的通用):Source在这个真实的例子中,LanguagesTags成员通过多对多正在生成N + 1个查询。
答案事实证明,AutoMapper有时会在映射可枚举类型时自动将ToList / ToArray添加到投影表达式,有时则不会。
规则似乎如下。如果目标可枚举类型可直接从源表达式类型分配,则AutoMapper直接使用源表达式。换句话说,如果以下赋值有效(伪代码):
dst.Member = src.Expression;

在这种情况下,您可以在映射表达式中包含或不包含ToList(因此选择加入EF Core相关查询优化)。
在所有其他情况下,AutoMapper会根据需要执行可枚举的元素映射,然后添加ToArrayToList。没有办法选择退出。
【使用Automapper优化相关子查询】很简单,如果目标可枚举元素类型为Dto(需要映射),则不要在源LINQ表达式中包含ToList,如果它是原始类型或实体类型,请包含ToList以避免N + 1个查询。如果目标集合类型是IEnumerable< T> ,则所有这些都适用。如果源表达式返回IReadOnlyCollection< T> ,AutoMapper将自动处理任何其他派生类型,如IReadOnlyList< T> ICollection< T> IList< T> List< T> T[]IEnumerable< TSource> 等。

    推荐阅读