代码之家  ›  专栏  ›  技术社区  ›  Collin Barrett

用Automapper优化相关子查询

  •  2
  • Collin Barrett  · 技术社区  · 6 年前

    更新: Automapper会在简单的情况下自动应用它,因为它 already adds a ToList() . 我所看到的导致我提出这个问题的问题是一个更为复杂的问题 SoftwareIds member N+1 . 看到了吗 this .).


    在efcore2.1中,我们支持添加 ToList() 在LINQ子查询上,以缓冲结果并避免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=> '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版

    真正的场景(我试图简化/使其通用): Source 在这个真实的例子中 Languages Tags 通过多对多的成员当前正在生成N+1查询。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Ivan Stoev    6 年前

    原来那个汽车制造商 有时 自动添加 ToList ToArray 映射可枚举类型时,有时不需要映射到投影表达式。

    规则似乎如下。如果目标可枚举类型可直接从源表达式类型赋值,则AutoMapper直接使用源表达式。换句话说,如果以下赋值有效(伪代码):

    dst.Member = src.Expression;
    

    在这种情况下,由你来决定 托利斯特 或者不在映射表达式中(因此选择EF Core相关查询优化)。

    在所有其他情况下,如果需要,AutoMapper执行可枚举元素映射,然后添加 ToArray公司 托利斯特 . 没有办法选择退出。

    很快,如果目标可枚举元素类型为if Dto(需要映射), 包括 在源LINQ表达式中,如果是基元或实体类型, 托利斯特 IEnumerable<T> IReadOnlyCollection<T> , IReadOnlyList<T> , ICollection<T> , IList<T> , List<T> T[] 如果源表达式返回,则自动映射程序将自动处理etc IEnumerable<TSource>