c# - 使用 Automapper 优化相关子查询

标签 c# linq entity-framework-core automapper

更新: 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: '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在这个实际示例中,通过多对多的 LanguagesTags 成员当前正在生成 N+1 个查询。

最佳答案

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

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

dst.Member = src.Expression;

在这种情况下,您需要包含 ToList或不在您的映射表达式中(因此选择 EF Core 相关查询优化)。

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

简而言之,如果目标可枚举元素类型为 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/

相关文章:

c# - EF Core 8 无法创建 'DbContext' 类型的 ''

c# - Input.GetMouseButtonUp 不可靠。 (统一)

c# - 有没有办法使用 LINQ 表达式填充集合?

c# - 来自 List<String> 的 FromSqlRaw 参数可以安全地避免 SQL 注入(inject)

c# - 使用linq逐项比较两个列表

c# - 实现 LINQ 表达式参数

.net-core - 将参数传递给EF Core的IDesignTimeDbContextFactory

c# - 使用 SQL 的 Unity 3D 安全身份验证

c# - 如何在 C# 应用程序中实现短信/短信/彩信

c# - 使用 win32 DLL 部署 XBAP