【问题标题】:Optimization of correlated subqueries with Automapper使用 Automapper 优化相关子查询
【发布时间】:2019-02-21 10:15:00
【问题描述】:

更新: Automapper 在简单的情况下会自动应用它,因为它already adds a ToList()。我看到的导致我提出这个问题的问题原来是一个更复杂的问题(SoftwareIds memberN+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 查询。

【问题讨论】:

  • 能否提供样例实体和dto模型。还有 AutoMapper 版本。
  • 因为 AutoMapper automatically includes ToList 为你服务。
  • 嗨@IvanStoev,我用模型和 AutoMapper 版本更新了问题。根据您的第二条评论,如果 AutoMapper 自动添加子查询上的 ToList() 缓冲,您知道为什么我的映射配置文件可能会创建 N+1 个查询吗?
  • 我先看看能不能复制。
  • 谢谢。我还刚刚在最底部添加了一个指向我要优化的实际映射配置文件的链接。

标签: c# linq entity-framework-core automapper


【解决方案1】:

事实证明,AutoMapper有时在映射可枚举类型时会自动将ToList / ToArray 添加到投影表达式中,有时不会。

规则似乎如下。如果目标可枚举类型可直接从源表达式类型分配,则 AutoMapper 直接使用源表达式。也就是说,如果下面的赋值是有效的(伪代码):

dst.Member = src.Expression;

在这种情况下,是否在映射表达式中包含 ToList 取决于您(因此选择加入 EF Core 相关查询优化)。

在所有其他情况下,AutoMapper 会根据需要执行可枚举元素映射,然后添加 ToArrayToList。没有办法退出。

简而言之,如果目标可枚举元素类型为 Dto(需要映射),不要在源 LINQ 表达式中包含 ToList,如果它是原始类型或实体类型,do 包括 ToList 以避免 N + 1 个查询。如果目标集合类型是IEnumerable&lt;T&gt;,所有这些都适用。如果源表达式返回IEnumerable&lt;TSource&gt;,AutoMapper 将自动处理任何其他派生集合类型,例如IReadOnlyCollection&lt;T&gt;IReadOnlyList&lt;T&gt;ICollection&lt;T&gt;IList&lt;T&gt;List&lt;T&gt;T[] 等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-20
    • 1970-01-01
    • 2014-03-26
    相关资源
    最近更新 更多