【问题标题】:AutoMapper ProjectTo with DbContext multi level Include()AutoMapper ProjectTo 与 DbContext 多级 Include()
【发布时间】:2020-02-14 11:40:29
【问题描述】:

我需要在 EF Core 选择期间执行多级 Include() 查询。我将 AutoMapper 与 ProjectTo<>() 一起使用。

我在映射ExplicitExpansion() 中指定了这意味着导航属性不会自动填充,因为我希望有可能多次执行相同的查询并且 一次Include() 导航属性,但第二次忽略它。

ProjectTo<>() 方法具有允许我将导航属性包含到我的选择中的参数,但我需要执行多级包含。这可能吗?像Include(e => e.Collection.Select(sc => sc.MyProperty)) 这样的语法在这种情况下不起作用。

我尝试将Include().ThenInclude() 用于DbContext,然后执行ProjectTo,但在这种情况下ProjectTo 会覆盖我的包含并且它们被忽略。

现在我不确定是否可以在映射中指定 ProjectToExplicitExpansion() 并进行多级包含?

【问题讨论】:

  • 你不需要Includedocs.automapper.org/en/latest/…
  • @LucianBargaoanu 好吧...我需要它,因为 AutoMapper 支持 ProjectTo 方法内的一级包含,为什么它不支持二级包含的包含。
  • 也许更仔细地阅读文档。或者查看 GitHub repo 中的相关测试。

标签: c# .net-core automapper entity-framework-core-3.1


【解决方案1】:

我尝试对 DbContext 使用 Include().ThenInclude(),然后执行 ProjectTo,但在这种情况下,ProjectTo 会覆盖我的包含并且它们被忽略。

此覆盖按预期工作。


Select() 覆盖 Include()

EF documentation 中明确提到了这一点:

如果您更改查询以使其不再返回查询开始时使用的实体类型的实例,则包含运算符将被忽略。

在以下示例中,包含运算符基于Blog,但随后使用Select 运算符将查询更改为返回匿名类型。在这种情况下,包含运算符不起作用。

包括

Include() 指示 EF 在获取请求的结果集时加载一些相关实体。此行为被添加到 EF 的默认加载行为中:

var people = db.People.ToList();

var peopleWithPets = db.People.Include(person => person.Pets).ToList();

通过添加Include(),您基本上扩展了在枚举集合时发生的加载行为(在本例中为ToList())。

选择

Select() 用您定义的新行为覆盖默认加载行为。

var people = db.People.ToList();

var names = db.People.Select(person => person.Name).ToList();

当您调用 Select() 时,您实际上是在指示 EF执行其默认加载行为(可能需要也可能不需要额外包含),而是完全加载您指定的内容(在本例中为person => person.Name)。


ProjectTo<>()Select() 的包装

您可以将ProjectTo<TDestination>() 视为一种SelectFactory,它根据Automapper 中配置的TDestination 映射生成适当的Select 语句。
在后台,EF 仍然执行Select(),因此在使用ProjectTo<>() 时,上述行为同样适用。

如果您想包含其他相关实体或其任何属性,则需要扩展 Automapper 映射,而不是在查询中使用 Include。如果您的映射包含其他字段,Automapper 将相应地扩展其底层 Select()

即使您已经能够使用 Include 包含相关实体,如果您从未将它们定义为映射,Automapper 无论如何都会忽略它们。

【讨论】:

  • 我清楚地理解 This overriding is working as intended. 所以,为什么 AutoMapper 打算支持包含 ExplicitExpansion 的字段但不应该支持二级包含。
  • @Alexey:您可以使用适当的映射来包含相关实体,但是当您还使用ProjectTo() 时,您不能使用Include 这样做。显式扩展需要Automapper 自动尝试填写每个 目标类型的属性,这可能会排除您显式映射相关实体的需要(即如果映射可以自动完成),但它仍然不会改变您的事实不应该在这里使用Include()
  • 我比较疑惑的是ProjectTo支持membersToExpand逻辑,但只有一层。
  • @AlexeyKlipilin:只有一层听起来像是一个任意规则,但它是有道理的,因为它专门防止循环引用变成无限循环。如果CompanyCompany.EmployeesEmployeeEmployee.Company (即该关系的另一边),那么你会陷入A 实例化B 实例化A 实例化B 实例化A 的无限循环......给定使用 EF 和导航属性实现 Automapper 的 ProjectTo 的可能性很高,这种循环引用几乎是不可避免的。
  • 但 AutoMapper 可以使用通常的 Include 方法轻松处理循环引用。
【解决方案2】:

你试过了吗?

dbContext.Entities.ProjectTo<EntityDto>(dest => dest.Collection.Select(item => item.MyProperty));

【讨论】:

  • 我试过了,但结果是空集合。似乎不是有效的表达方式。
  • 现在是 EF Core 5,这种方法有效
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-29
  • 2020-12-09
  • 1970-01-01
  • 2019-07-24
相关资源
最近更新 更多