2010-05-16 110 views
3

我有一個userList,有些用戶沒有名稱(空)。如果我運行第一個LINQ查詢,我得到一個錯誤,說「對象引用未設置爲對象的實例」錯誤。LINQ查詢檢查爲空

var temp = (from a in userList 
      where ((a.name == "john") && (a.name != null)) 
      select a).ToList(); 

但是,如果我通過將檢查空門前切換順序,然後它不拋出任何錯誤:

var temp = (from a in userList 
      where ((a.name != null) && (a.name == "john")) 
      select a).ToList(); 

這是爲什麼?如果這是純粹的C#代碼(而不是LINQ),我認爲兩者都是一樣的。我沒有SQL分析器,我只是好奇他們在SQL級別上進行翻譯時會有什麼不同。

回答

10

在C#中,&& operator是短路的,所以如果第一個條件返回false,則根本不會執行第二個條件。從MSDN:

The conditional-AND operator (&&) performs a logical-AND of its bool operands, but only evaluates its second operand if necessary.

|| operator的行爲以類似的方式,只是它不評估,如果第一個返回true的第二個參數。


雖然我不認爲這是完整的故事。我的帖子的其餘部分包括以下幾點:

  • 您可以使用DataContext.Log記錄SQL語句。
  • 無論您編寫哪種方式,您的查詢都不應該生成錯誤。
  • LINQ到對象和LINQ to SQL之間的行爲有所不同。
  • 您的過濾可能在本地而不是在數據庫中執行。

您可以輕鬆地在Visual Studio中查看生成的SQL,而不需要SQL事件探查器。您可以將鼠標懸停在LINQ to SQL查詢對象上,它將顯示SQL。或者你也可以使用DataContext.Log記錄的SQL語句,比如像這樣:

TextWriter textWriter = new StringWriter(); 
using (var dc = new UserDataContext()) 
{ 
    dc.Log = textWriter; 
    var userList = dc.Users; 
    var temp = (from a in userList 
       where (a.Name.ToString() == "john") && (a.Name != null) 
       select a).ToList(); 
} 
string log = textWriter.ToString(); 

您也可以登錄到一個文件甚至Console.Out

dc.Log = Console.Out; 

這樣做,你可以看到,查詢看起來像這樣,雖然你可能會有更多的列在選擇列表:

SELECT [t0].[Name] 
FROM [dbo].[User] AS [t0] 
WHERE ([t0].[Name] = @p0) AND ([t0].[Name] IS NOT NULL) 

另一點是,您的查詢不應該產生一個錯誤。即使a.name爲空,a == "john"仍然可以工作 - 它只會返回false。

最後,C#的正常工作方式與LINQ to SQL的工作方式有所不同。你不應該從數據庫中得到一個空的異常。爲了證明這一點,我會做一個小的修改您的查詢 - 添加ToStringa.Name

var temp = (from a in userList 
      where (a.Name.ToString() == "john") && (a.Name != null) 
      select a).ToList(); 

現在這個失敗對LINQ與一個NullReferenceException對象,但它與LINQ工作沒有拋出異常的SQL。所以我懷疑你已經把數據庫中的所有項目加載到內存中,並在本地進行過濾。換句話說,也許你有這樣的事情:

var userList = dc.Users.ToList(); 

,而不是這將使數據庫做過濾以下:

var userList = dc.Users; 

所以我懷疑還有更多的這個問題比滿足眼。也許你可以提供更多的細節。

+0

很好的回答 - 甜蜜和簡單的 – 2010-05-16 01:57:17

+0

非常感謝...... – userb00 2010-05-16 01:59:37

+0

@Preet僧伽:不再那麼短。仔細看看它,我不確定簡單的答案能夠充分解釋行爲。 – 2010-05-16 02:23:37

0

關於這個問題,如何轉換SQL - 我認爲SQL具有相同的短路語義,所以SQL轉換器只保留生成的查詢中的條件順序。

例如以下兩個LINQ條款:

where p.CategoryID != null && p.CategoryID.Value > 1 
where p.CategoryID.Value > 1 && p.CategoryID != null 

Translet以下兩個SQL子句:

WHERE ([t0].[CategoryID] IS NOT NULL) AND (([t0].[CategoryID]) > @p0) 
WHERE (([t0].[CategoryID]) > @p0) AND ([t0].[CategoryID] IS NOT NULL) 
+0

我不認爲SQL具有與C#相同的短路語義。看到這個問題http://stackoverflow.com/questions/2842334/linq-query-checks-for-null/2842340#2842340和這篇文章:http://weblogs.sqlteam.com/mladenp/archive/2008/02/ 25/How-SQL-Server-short-circuits-WHERE-condition-evaluation.aspx – 2010-05-16 02:55:57

+0

@Mark:有趣的 - 在這種情況下可能並不重要,因爲SQL查詢在處理'null'時不會失敗。 。 – 2010-05-16 12:56:34