2

我們有一個名爲Student的表。該表格有一個名爲Homeroom的字段,其中值是學生班主任的房間號碼。該值可以爲null。防止LINQ to Entity加入NULL檢查

我們有第二個表Staff。該表還有一個名爲Homeroom的字段,用於指示教師分配給哪個教室。該值可以爲null。

但是,當學生的Homeroom爲空時,不應返回Staff記錄。

我們過去利用了這樣一個事實,即檢查兩個null字段的相等性總是在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 

學生會被退回,但沒有老師。

我們使用實體框架和Code First POCO對象。所以,我們有一個Student對象和一個Staff對象。當我們重新創建SQL在LINQ:

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; 

生成的SQL包含兩個班主任場空校驗:

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)) 
    ) 

這將返回學生,並確定誰沒有一個班主任任何人員。根據我們以前編寫SQL語句的方式,這不是我們想要或預期的。

周圍有一個明顯的方法是確保我們不包括沒有班主任(join homeroomTeacher in repo.GetStaff().Where(staff => staff.Homeroom != null)人員。但是,有沒有在LINQ另一種方式,以防止對域null檢查時加入他們?

回答

9

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; 

僅供參考,UseDatabaseNullSemantics引入來解決-了這一行爲,但它看起來像他們忘了JOIN語義,只把它應用到WHERE語義。

這種原始的說法是錯誤的 - EF 4.3.1顯示出相同的連接行爲:

這基本上意味着現在的一些結果集是EF 6不同,相比於以前的版本。在我看來,這是一筆巨大的交易!因爲它將錯誤引入我的工作解決方案中!

我提出一個問題,在CodePlex上:https://entityframework.codeplex.com/workitem/2006

0

我沒有方便的數據模型,以測試這一點,但它應該有可能通過合併班主任值不同的字符串來模擬SQL的null != null行爲(或整數,或任何類型的):

from student in repo.GetStudents() 
join homeroomTeacher in repo.GetStaff() 
    on new { 
     student.Building, 
     Room = student.Homeroom ?? "A" 
    } 
    equals new { 
     homeroomTeacher.Building, 
     Room = homeroomTeacher.Homeroom ?? "B" 
    } 
into roj2 
from homeroomTeacherRoj in roj2.DefaultIfEmpty() 
select student.Id, homeroomTeacherRoj.Name; 

這樣,如果student.HomeroomhomeroomTeacher.Homeroom都爲空,則co在加入比較會"A" == "B",這將返回false。

Context.Configuration.UseDatabaseNullSemantics = true; 

所以,在以「加盟」:如果你移動你的加入到where子句,那麼的DbContext對象具有以下設置將關閉(EF 6引入)NULL檢查行爲