更新:
自动映射器already adds a ToList()
在简单的情况下会自动应用。我所看到的导致我提出这个问题的问题原来是一个更为复杂的问题(SoftwareIds member是N+1
的元凶。请参阅this。)
在EF Core 2.1中,我们获得了在LINQ子查询上添加ToList()
的支持,以缓冲结果并避免进行N + 1个数据库查询。 (Docs)在针对DbContext的普通LINQ查询上非常有用。
但是,如果我有一个自动映射程序配置文件,该配置文件会导致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在此真实示例中,目前正在通过多对多的方式生成Languages
和Tags
成员N + 1个查询。
答案 0 :(得分:2)
事实证明,当映射可枚举类型时,AutoMapper有时有时自动向投影表达式添加ToList
/ ToArray
。
规则似乎如下。如果可以从源表达式类型直接分配目标可枚举类型,则AutoMapper将直接使用源表达式。换句话说,如果以下分配有效(伪代码):
dst.Member = src.Expression;
在这种情况下,由您自己决定是否在映射表达式中包含ToList
(因此可以选择加入EF Core相关查询优化)。
在所有其他情况下,AutoMapper会根据需要执行可枚举的元素映射,然后添加ToArray
或ToList
。无法选择退出。
简而言之,如果目标可枚举元素类型为Dto(需要映射),则不要在源LINQ表达式中包含ToList
(如果它是原始类型或实体类型), 包括ToList
可以避免N + 1个查询。如果目标集合类型为IEnumerable<T>
,则所有这些都适用。其他任何派生的集合类型,例如IReadOnlyCollection<T>
,IReadOnlyList<T>
,ICollection<T>
,IList<T>
,List<T>
,T[]
等,都会由AutoMapper自动处理源表达式返回IEnumerable<TSource>
的情况。