gpt4 book ai didi

mysql - Entity Framework Core Linq NULL 不起作用

转载 作者:行者123 更新时间:2023-11-29 02:15:07 24 4
gpt4 key购买 nike

我正在使用 Entity Framework Core 和 Linq 编写查询以获取我对象上的 EndDate 属性为 NULL 的所有条目。但是,EF 不会将查询转换为正确的 SQL 以过滤掉 EndDate 不为 NULL 的对象。我正在使用带有这些包的 MySQL 数据库:

"MySql.Data.Core": "7.0.4-IR-191",
"MySql.Data.EntityFrameworkCore": "7.0.4-IR-191",

这是我的查询:

var employees = (from emp in _context.Employees.ToList()
join loc in _context.Locations.ToList()
on emp.HomeLocationId equals loc.LocationId
join rate in _context.EmployeeRates.ToList()
on emp.EmployeeId equals rate.EmployeeId
where rate.EndDate == null
select emp).ToList();

这是我的 EndDate 属性声明:

public DateTime? EndDate { get; set; }

生成的 SQL 根本不包含 WHERE 子句。我已将此查询手动转换为 MySQL,并且运行良好:

SELECT e.FirstName, e.LastName, er.Rate, er.StartDate, er.EndDate
FROM qasdb.employees as e
JOIN qasdb.employeerates as er on er.EmployeeId = e.EmployeeId
JOIN qasdb.locations as l on l.LocationId = e.HomeLocationId
WHERE e.FirstName='Todd' AND er.EndDate is null

这是 EF Core 的问题吗?是否有已知的变通方法可以使 Null 比较起作用?

编辑

这是生成的 SQL。它看起来在做几个查询:

SELECT e.EmployeeRateId, e.EmployeeId, e.EndDate,
e.LastModifiedBy, e.Rate, e.StartDate FROM employeerates
AS e

SELECT emp.EmployeeId, emp.ActiveFlag, emp.City,
emp.CreateStamp, emp.Email, emp.EmergencyContactName,
emp.EmergencyContactPhone, emp.FirstName,
emp.HomeLocationId, emp.JobClass, emp.LastModifiedBy,
emp.LastName, emp.PhoneNumber, emp.Ssn, emp.State,
emp.Street, emp.UpdateStamp, emp.Zip FROM employees
AS emp
INNER JOIN locations AS loc ON emp.HomeLocationId = loc.LocationId

编辑#2

当我从每一行中删除 ToList() 调用时,将按预期生成 SQL:

SELECT emp.EmployeeId, emp.ActiveFlag, emp.City,
emp.CreateStamp, emp.Email, emp.EmergencyContactName,
emp.EmergencyContactPhone, emp.FirstName,
emp.HomeLocationId, emp.JobClass, emp.LastModifiedBy,
emp.LastName, emp.PhoneNumber, emp.Ssn, emp.State,
emp.Street, emp.UpdateStamp, emp.Zip FROM employees
AS emp
INNER JOIN locations AS loc ON emp.HomeLocationId = loc.LocationId
INNER JOIN employeerates AS rate ON emp.EmployeeId = rate.EmployeeId
WHERE rate.EndDate IS NULL

但是,当我删除 .ToList() 调用时,我丢失了从 Employee 对象到 EmployeeRates 列表的导航属性。以下是我的员工实体的设置方式:

 public class Employee : BaseEntity
{
public int EmployeeId { get; set; }

......


public string JobClass { get; set; }

public int HomeLocationId { get; set; }




//Navigation Properties
public virtual Location HomeLocation { get; set; }

public virtual List<EmployeeRate> EmployeeRates { get; set; }

}

在删除 ToList() 调用后,HomeLocation 和 EmployeeRates 对象都返回“null”。

最佳答案

您的第一个查询在每个 DbSet 之后包含 ToList(),这会将所有这些表中的所有数据带到内存中。每当调用 ToList() 时,EF 都会执行查询。因此,即使您一起编写了整个 linq 查询,EF 也有 3 个小查询要在那里处理(加载每个 DbSet),因此您会得到 3 个不同的查询被发送到数据库。 EF 将从这些查询生成实体集合,其他所有内容都将在客户端进行评估,因此您看不到 where 子句被转换为服务器,因为它根本不是提供给 EF 的查询的一部分。在此解决方案中,您可以看到加载的导航属性,因为所有数据都加载到内存中,然后 EF 将修复导航属性以填充它们。 (这样内存中的所有数据都处于一致状态。)

当您从所有 DbSet 中删除 ToList() 调用时,它将变成一个传递给 EF 的查询。 (最后一个 ToList() 调用执行)因此 EF 将处理查询并翻译 where 子句,但由于您只投影出 Employee 对象,因此 EF 将仅获取属性它不会检索任何相关数据。如果您想填充导航属性,即加载相关数据,则必须使用 Include 语法明确告诉 EF。

您要查找的查询是

var result = (from e in db.Employees.Include(e => e.HomeLocation).Include(e => e.EmployeeRates)
join er in db.EmployeeRates on e.Id equals er.EmployeeId
where er.EndDate != null
select e).ToList();

对于您希望在最终结果中填充的每个导航,查询都有 Include。由于过滤包含在 EF 中仍然不受支持,(请参阅 https://github.com/aspnet/EntityFramework/issues/1833)您不能直接在 rate.EndDate 上指定 where 子句。因此,您需要手动加入该表并在 EndDate 上应用 where 条件。由于 HomeLocation 是一对一导航,因此 EF 将仅在主查询中为其检索相关数据(以填充导航)。 EmployeeRates 是集合导航,因此 EF 将发送单独的查询以加载相关员工的相关数据。重要的一点,您不需要手动加入 HomeLocation。 include 会为你做到这一点。您需要手动加入 EmployeeRate 仅用于过滤。

以下是SQL生成的主要查询

    SELECT [e].[Id], [e].[HomeLocationId], [l].[Id]
FROM [Employees] AS [e]
INNER JOIN [EmployeeRates] AS [er] ON [e].[Id] = [er].[EmployeeId]
INNER JOIN [Locations] AS [l] ON [e].[HomeLocationId] = [l].[Id]
WHERE [er].[EndDate] IS NOT NULL
ORDER BY [e].[Id]

关于mysql - Entity Framework Core Linq NULL 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41065494/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com