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中是否有另一种方法可以防止在加入字段时对字段进行空检查?
如果将连接移动到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