mysql - Entity Framework Core Linq 其中 NULL 不起作用

标签 mysql entity-framework linq entity-framework-core

我正在使用 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 的问题吗?是否有已知的解决方法可以使空比较发挥作用?

编辑

这是生成的 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 列表的导航属性。以下是我的 Employee 实体的设置方式:

 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 查询,仍有 3 个小查询供 EF 处理(加载每个 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/

相关文章:

c# - 如何启用映射实体的私有(private)属性

c# - Entity Framework 仅在更新时抛出异常 - 无效的对象名称 'dbo.BirdBrain.service'

c# - Entity Framework Core LINQ 创建查询时遇到问题(选择案例存在)

c# - CosmosDB - UTC 查询的 DateTimeOffset 问题

c# - Entity Framework - 查询可为空列的问题

c# - 动态Where Linq 到实体

mysql - 将数据从 MySQL 导出到“我的文档”中的文件

mysql - 如何为多个表中的值添加 SQL 约束

php - MySQL 插入不接受十进制值

PHP MYSQL文件内容转义问题