防止LINQ到实体联接中的NULL检查

sco*_*rin 4 sql linq-to-entities entity-framework outer-join ef-code-first

我们有一张叫做的桌子Student.该表有一个名为的字段Homeroom,其中值是学生教室的房间号.该值可以为null.

我们有一个名为的第二个表Staff.该表还有一个字段,Homeroom用于指示教师分配到哪个教室.该值可以为null.

但是当学生Homeroom为空时,Staff不应返回记录.

我们曾经利用这样的事实:检查两个空字段的相等性总是在SQL中返回false.通过SQL,这就是我们获取所需数据的方式:

SELECT STUDENT.ID, STAFF.NAME as [Homeroom Teacher]
FROM STUDENT
LEFT OUTER JOIN STAFF ON
    STAFF.BUILDING = STUDENT.BUILDING AND
    STAFF.HOMEROOM = STUDENT.HOMEROOM
Run Code Online (Sandbox Code Playgroud)

学生将被退回,但没有老师.

我们正在使用Entity Framework和Code First POCO对象.所以,我们有一个Student对象和一个Staff对象.当我们在LINQ中重新创建此SQL时:

from student in repo.GetStudents()
join homeroomTeacher in repo.GetStaff()
    new { student.Building, Room = student.Homeroom }
     equals new { homeroomTeacher.Building, Room = homeroomTeacher.Homeroom }
into roj2
from homeroomTeacherRoj in roj2.DefaultIfEmpty()
select student.Id, homeroomTeacherRoj.Name;
Run Code Online (Sandbox Code Playgroud)

生成的SQL包含两个Homeroom字段的NULL检查:

SELECT STUDENT.ID, STAFF.NAME
FROM STUDENT AS [Extent1]
LEFT OUTER JOIN [dbo].[STAFF] AS [Extent2] ON 
    ([Extent1].[BUILDING] = [Extent2].[BUILDING]) AND 
    (
        ([Extent1].[HOMEROOM] = [Extent2].[HOMEROOM]) OR 
        (([Extent1].[HOMEROOM] IS NULL) AND ([Extent2].[HOMEROOM] IS NULL))
    )
Run Code Online (Sandbox Code Playgroud)

这将返回学生,以及没有定义教室的任何工作人员.根据我们之前编写SQL语句的方式,这不是我们想要或期望的.

一个显而易见的方法是确保我们不包括没有教室的工作人员(join homeroomTeacher in repo.GetStaff().Where(staff => staff.Homeroom != null).但LINQ中是否有另一种方法可以防止在加入字段时对字段进行空检查?

Sim*_*ell 9

如果将连接移动到where子句中,则DbContext对象上的以下设置将关闭(引入的EF 6)NULL检查行为:

Context.Configuration.UseDatabaseNullSemantics = true;
Run Code Online (Sandbox Code Playgroud)

因此,要在where子句中"加入",可以将查询拆分为2个IQueryable对象

var subquery = from homeroomTeacher in repo.GetStaff()
               where ...
               select homeroomTeacher;

var query = from student in repo.GetStudents()
            where subquery.Any(homeroomTeacher => 
                 homeroomTeacher.xxx == student.xxx) -- simplified join for demo code
            select student;
Run Code Online (Sandbox Code Playgroud)

fyi,引入了UseDatabaseNullSemantics来修复这种行为,但看起来它们忘记了JOIN语义并且只将它应用于WHERE语义.

这个原始陈述是错误的 - EF 4.3.1表现出相同的JOIN行为:

这实际上意味着与以前的版本相比,EF 6现在有些结果集不同.在我看来,这是一个很大的交易!!!! 因为它将错误引入我的工作解决方案!!!!

我在codeplex上提出了一个问题:https://entityframework.codeplex.com/workitem/2006