更新:
自动映射器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在这个真实的示例中,通过多对多的
Languages
和Tags
成员当前正在生成N + 1查询。 最佳答案
事实证明,当映射可枚举类型时,AutoMapper有时会自动将ToList
/ ToArray
添加到投影表达式中,有时却不会。
规则似乎如下。如果可以从源表达式类型直接分配目标可枚举类型,则AutoMapper将直接使用源表达式。换句话说,如果以下分配有效(伪代码):
dst.Member = src.Expression;
在这种情况下,由您决定是否在映射表达式中包含
ToList
(因此,选择加入EF Core相关查询优化)。在所有其他情况下,如果需要,AutoMapper会执行可枚举的元素映射,然后添加
ToArray
或ToList
。无法选择退出。简短地说,如果目标可枚举元素类型为Dto(需要映射),则在源LINQ表达式中不要包含
ToList
,如果它是基本类型或实体类型,则请包含ToList
以避免N + 1查询。如果目标集合类型为IEnumerable<T>
,则所有这些都适用。如果源表达式返回IReadOnlyCollection<T>
,AutoMapper将自动处理其他任何派生的集合类型,例如IReadOnlyList<T>
,ICollection<T>
,IList<T>
,List<T>
,T[]
,IEnumerable<TSource>
等。关于c# - 使用Automapper优化相关子查询,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52368567/