使用Automapper优化相关子查询
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用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在这个真实的例子中,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>
等。
以上是关于使用Automapper优化相关子查询的主要内容,如果未能解决你的问题,请参考以下文章