linq 顶级EF Core预测中的客户评估

zrfyljdw  于 2023-11-14  发布在  其他
关注(0)|答案(1)|浏览(129)

假设我执行了一个查询并投射到一个匿名类型中;这将在服务器上执行评估:

var people = await context
  .People
  .OrderBy(x => x.Name)
  .Select(x => new { x.Id, x.Surname, x.Forename })
  .ToListAsync();

字符串
但是假设我执行一个查询,并且需要投影到一个具体类型中。
选项1:将结果Map到具体类型:

var people = (await context
  .People
  .OrderBy(x => x.Name)
  .Select(x => new { x.Id, x.Surname, x.Forename })
  .ToListAsync())
  .Select(x => new PersonDto(x.Id, x.Surname, x.Forename));


选项2:在 “顶层投影” 中使用具体类型:

var people = await context
  .People
  .OrderBy(x => x.Name)
  .Select(x => new PersonDto(x.Id, x.Surname, x.Forename));
  .ToListAsync()


关于(2),文档中指出,在顶级投影中,一些评估在数据库中执行,一些在客户端执行。(但文档显示了一个匿名类型的客户端函数的示例,因此它与我的用例不同。)
在这个具体的例子中,我假设所有的计算都是在服务器上执行的,并且(2)只是(1)的捷径,即它们在功能上是等价的,这对吗?

u5rb5r59

u5rb5r591#

提问:

  • 所有的评估都是在服务器上执行的,而(2)只是(1)的捷径,即它们在功能上是等同的?*

回答

显然,PersonDto对象是在客户端示例化的,但是,EF能够从数据库中获取三个构造函数参数值x.Id, x.Surname, x.Forename。只有这三个值(Select id, surname, forename from people order by name):
EF Core支持顶层投影中的部分客户端评估(本质上是对Select()的最后一次调用)。如果查询中的顶级投影不能被转换到服务器,EF Core将从服务器获取任何所需的数据,并在客户端上评估查询的剩余部分。如果EF Core在顶级投影之外的任何地方检测到表达式,无法转换到服务器,则会抛出运行时异常
详细说明见https://learn.microsoft.com/en-us/ef/core/querying/client-eval文档。

测试

下面是EF将顶级投影转换为SQL的示例。表达式:

var result = 
    dbcontext.
    Customers.
    Select(x => new PersonName2CharsDto(x.Name.Substring(0,2))).
    ToList();

字符串
生成的sql(对于sqlite):

SELECT substr("c"."Name", 0 + 1, 2)
FROM "Customers" AS "c"

相关问题