Mysql 实体框架核心Linq,其中NULL不起作用

Mysql 实体框架核心Linq,其中NULL不起作用,mysql,entity-framework,linq,entity-framework-core,Mysql,Entity Framework,Linq,Entity Framework Core,我正在使用EntityFrameworkCore和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 _con

我正在使用EntityFrameworkCore和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列表的导航属性。以下是如何设置我的员工实体:

 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; }

 }
公共类员工:BaseEntity
{
public int EmployeeId{get;set;}
......
公共字符串JobClass{get;set;}
public int HomeLocationId{get;set;}
//导航属性
公共虚拟位置HomeLocation{get;set;}
公共虚拟列表雇员{get;set;}
}

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

是否先使用代码

检查你的地图课上是否没有这个


this.Property(t=>t.EndDate).IsRequired()

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

当您从所有数据库集中删除
ToList()
调用时,它将成为一个传递给EF的查询。(最后一个
ToList()
调用执行)因此EF将处理查询并转换where子句,但由于您仅投影
Employee
对象,EF将仅获取其属性,而不会检索任何相关数据。如果要填充导航属性,即加载相关数据,则必须使用
Include
synatax显式告知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();
对于要在最终结果中填充的每个导航,查询都有
包含
。由于EF中仍然不支持筛选的include(请参阅),因此不能直接在
rate.EndDate
上指定where子句。因此,您需要手动连接该表,并在
EndDate
上应用where条件。由于
HomeLocation
是一对一的导航,EF将仅在主查询中检索相关数据(用于填充导航)
EmployeeRates
是集合导航,因此EF将发送一个单独的查询来加载相关员工的相关数据。重要的一点是,您不需要手动加入
HomeLocation
。我会帮你的。您需要手动加入
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]

你能发布ef核心生成的sql吗?另外,为什么要在每个in中调用ToList()方法?请删除所有
ToList
调用(final调用除外),查询应按预期进行。目前,您正在告诉EF加载内存中的所有表,并在其中执行联接/筛选。@IvanStoev,我按照您的建议执行了操作,但在执行此操作后,我将导航属性丢失到EmployeeRates对象so@H.Herzl,我已经用SQL更新了我的帖子。谢谢我不知道你说的“地图课”是什么意思。你能给我一些关于去哪里看的见解吗?也许你是指我的DbContext类中的OnModelCreating方法?你在Ef核心中使用了什么?数据注释或FluentAPI@H.Herzl,我两者都用了一点。数据注释缺乏核心功能。例如,没有外键注释,所以对于外键,我一直在使用Fluent API。您可以使用数据注释进行fk定义,但是在您的情况下,这些名称空间中的属性的强制列SADD Key和ForeignKey属性似乎存在问题:System.ComponentModel.DataAnnotations&System.ComponentModel.DataAnnotations.SchemaThis由于正在加载导航属性,因此部分工作正常。但是,它仍然包括employee对象上日期不为null的employeeRates。我只查找具有EndDate==null的employeeRate记录的记录。这就是筛选的include所做的,它还不受支持。