更新:
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: 'Could not parse expression 'MyDto.MyCollectionPropMany.Select(la => la.MyCollectionEntity).ToList()': This overload of the method 'System.Linq.Enumerable.ToList' is currently not supported.'
有没有办法在 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; }
...
}
自动映射器v7.0.1
真实场景(我试图简化/使SO通用):Source在这个实际示例中,通过多对多的 Languages
和 Tags
成员当前正在生成 N+1 个查询。
最佳答案
事实证明,AutoMapper有时会自动添加 ToList
/ToArray
映射枚举类型时映射到投影表达式,有时不会。
规则似乎如下。如果目标枚举类型可以直接从源表达式类型分配,则 AutoMapper 直接使用源表达式。换句话说,如果以下赋值有效(伪代码):
dst.Member = src.Expression;
在这种情况下,您需要包含 ToList
或不在您的映射表达式中(因此选择 EF Core 相关查询优化)。
在所有其他情况下,如果需要,AutoMapper 会执行可枚举元素映射,然后添加 ToArray
或ToList
。没有办法选择退出。
简而言之,如果目标可枚举元素类型为 Dto(需要映射),则不包括 ToList
在源 LINQ 表达式中,如果它是原始类型或实体类型,请包含 ToList
避免N+1次查询。如果目标集合类型为 IEnumerable<T>
,则所有这些都适用。任何其他派生的集合类型,如 IReadOnlyCollection<T>
, IReadOnlyList<T>
, ICollection<T>
, IList<T>
, List<T>
, T[]
如果源表达式返回 IEnumerable<TSource>
等,AutoMapper 将自动处理.
关于c# - 使用 Automapper 优化相关子查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52368567/