2010-01-19 14 views
20

我遇到了一個linq-to-sql的奇怪問題。在下面的例子中,Linq where列==(空引用)與列== null不一樣

var survey = (from s in dbContext.crmc_Surveys 
            where (s.crmc_Retail_Trade_Id == tradeId) && (s.State_.Equals(state)) 
            select s).First(); 

如果tradeId爲空,它不表現爲,如果我指定的空明確這樣代替,

var survey = (from s in dbContext.crmc_Surveys 
            where (s.crmc_Retail_Trade_Id == null) && (s.State_.Equals(state)) 
            select s).First(); 

這是我所期望的行爲。實際上它不會返回任何東西,除非這兩個值都是非空的。我無法弄清楚如何完成幾個不同的linq查詢。有任何想法嗎?

回答

26

變化where (s.crmc_Retail_Trade_Id == tradeId)

where (s.crmc_Retail_Trade_Id == tradeId || 
     (tradeId == null && s.crmc_Retail_Trade_Id == null)) 

編輯 - 由布蘭特Lamborn基於this post,它看起來像下面會做你想要什麼:

where (object.Equals(s.crmc_Retail_Trade_Id, tradeId)) 

Null Semantics (LINQ to SQL) MSDN頁面鏈接到一些有趣的info:

LIN Q to SQL不強加C#null或 Visual Basic沒有比較 SQL上的語義。比較運算符 在語法上被翻譯爲它們的 SQL等效項。語義反映 由服務器或 連接設置定義的SQL語義。兩個空值 在默認情況下被認爲是不相等 SQL Server設置(儘管可以通過 更改設置來更改 語義)。無論如何,LINQ to SQL 不考慮 查詢翻譯中的服務器設置。

與字面無效 (無)的比較轉換爲 適當的SQL版本(爲空或 非空)。

歸類中null(無)的值由SQL Server定義; LINQ to SQL不會更改 排序規則。

+1

是的,我想這是一個明顯的答案。但是詢問頭腦想要知道爲什麼常量null與指向null的變量不同。 – Boog

+0

我懷疑Joel Coehoorn是正確的,你的問題中的第二種情況被轉換爲直接指定null的sql查詢。 – jball

+0

這似乎是微軟的LINQ解析器不妥善處理空對象引用一個非常大的缺陷,甚至錯誤,但我相信你的話了吧。 – Boog

2

不知道這個,但我懷疑當linq-to-sql將其轉換爲sql查詢字符串時,您會得到一個稍微不同的表達式,直接指定null,這樣在某些時候您最終將NULL與自身進行比較, = NULL被定義爲false。

+1

除非ANSI_NULLS設置爲OFF。但那會導致宇宙崩潰。 – womp

1

我不熟悉使用LINQ,但一般:

NULL代表缺失,未知或不確定的價值。嚴格來說,一個變量不能等於NULL;提供這種結構的低級語言通常是爲了方便起見,因爲沒有簡單的選擇 - 在更高級別上,依賴ISNULL,defined或您的語言提供的任何功能通常會更好。

一個未定義的變量不等於另一個未定義的變量(同樣適用於NULL == NULL)。 Joe Celko有一個很好的例子,寫一個查詢來查找所有頭髮顏色與他們駕駛的車輛顏色相匹配的人。這個查詢應該與一個到處走動的禿頭男人相匹配嗎?

+1

我認爲,一個男人不存在的頭髮顏色被認爲是與他不存在的汽車油漆相匹配的可靠方法。 – jball

+0

在低級別或高級語言中,null是十六進制值0x0,null == null是true。現在我知道在SQL中這不是真的,但C#不是SQL,我們預計這會持續。 Linq-to-Sql應該是C#用戶的抽象。如果你問我MS搞砸了這隻狗,我錯了嗎? – Boog

+0

確實。我更想向詢問心靈解釋,想知道爲什麼一個常量null與指向一個變量的變量不同。在大多數情況下,null相當於0x0,如果你需要一個指向內存段開始的指針,這是一個嚴重的問題(幸好這不再是問題)。我說等價,因爲我認爲與平等存在微妙的差異。這就像是說1.999999999 ...不等於2,這只是一個數學上的不便,他們碰巧是相同的價值。 – Duncan

2

另一個選項來解決這個問題,因爲我碰到這個問題跑了爲好。

where (tradeId == null ? s.crmc_Retail_Trade_Id == null : s.crmc_Retail_Trade_Id == tradeId)