2009-12-20 82 views
0

我試圖在LinqPad中編寫Linq-To-SQL查詢來幫助將用戶從舊錶遷移到新表。此遷移的一部分是將所有地址存儲在單獨的表中。我使用下面的查詢,以確定是否用戶的地址在新表中存在(所以我沒有重複的條目):Linq-to-SQL拋出NullReferenceException,儘管檢查爲空參數

var addresses = from a in Addresses where ((u.Street_address == null && a.Street1 == null) || (u.Street_address != null && a.Street1 != null && a.Street1.ToLower() == u.Street_address.ToLower())) 
           && ((a.City == null && u.City == null) || (a.City != null && u.City != null && a.City.ToLower() == u.City.ToLower())) 
           && ((a.State == null && u.State == null) || (a.State != null && u.State != null && a.State.ToLower() == u.State.ToLower())) 
           && ((a.Zip == null && u.Zipcode == null) || (a.Zip != null && u.Zipcode != null && a.Zip.ToLower() == u.Zipcode.ToLower())) 
           select a; 

在這裏,「U」代表的老用戶。舊錶中的某些地址包含Street_address,City,State和/或Zipcode的空條目。此外,一些地址是重複的,除了套管(因此ToLower())。

儘管在查詢中檢查了空參數,但如果任何用戶的地址參數爲空,我仍然會收到NullReferenceException。

我做錯了什麼?還是有更好的方法來完成我所需要的?

回答

2

UPDATE:

嗯,看起來這是比我原來想象要複雜得多。結果String.Equals與StringComparison超載是not supported by Linq-to-SQL。但是,出現錯誤的事實意味着Linq-to-SQL試圖將整個表達式轉換爲SQL。這反過來又意味着所有的比較都會根據數據庫的本地整理髮生 - 默認情況下不區分大小寫。因此即使Linq-to-SQL不支持不區分大小寫的比較,您可能也不需要區分大小寫的比較,因爲您可以依靠SQL Server默認進行比較。

所以,只要你有沒有從不區分大小寫(默認值)區分大小寫改變你的字符串列的排序規則在你的表,下面的代碼應該工作:

var addresses = from a in Addresses 
       where String.Equals (u.Street_address, a.Street1) 
         && String.Equals (u.City, a.City) 
         && String.Equals (u.State, a.State) 
         && String.Equals (u.ZipCode, a.Zip) 
       select a; 

有可能這個可能工作太:

var addresses = from a in Addresses 
       where u.Street_address == a.Street1 
         && u.City == a.City 
         && u.State == a.State 
         && u.ZipCode == a.Zip 
       select a; 

但是,根據我的this MSDN article(摘錄如下)讀書,我懷疑只有使用==(而不是String.Equals()可能無法正常工作):

null語義

的LINQ to SQL不 上 SQL徵收空比較語義。比較運算符是 ,它們的語法翻譯爲它們的SQL 等效項。由於這個原因, 語義反映了 由服務器或連接 設置定義的SQL語義。例如,在默認 SQL Server設置下,兩個空值 被視爲不相等,但您可以更改設置以更改 語義。當LINQ to SQL 翻譯查詢時,不會考慮服務器設置。

與立即空值的比較是 翻譯爲適當的SQL 版本(爲空或不爲空)。

換句話說,如果我正確地讀這MSDN文本,這聽起來像LINQ到SQL轉換成=== T-SQL,同時(因爲你的實驗顯示)String.Equals正確翻譯作爲IS NULL的支票,然後使用=進行支票。如果你有機會測試==,我很樂意看看Linq-to-SQL是否發出IS NULL檢查。由於這裏的複雜性(Linq-to-SQL將C#轉換爲SQL,並返回C#),在這種情況下,最好的辦法就是嘗試多種變體(例如==和Equals()),然後選擇一個是有效的,因爲有足夠多的移動部件,所以很難提前預測哪個變化最好。

OLD ANSWER(忽略此):

考慮使用靜態String.Equals方法代替==ToLower()。您將避免空引用問題(並簡化代碼),因爲空值可以傳入該方法,並支持不區分大小寫的檢查。

var addresses = from a in Addresses 
       where String.Equals (u.Street_address, a.Street1, StringComparison.OrdinalIgnoreCase) 
         && String.Equals (u.City, a.City, StringComparison.OrdinalIgnoreCase) 
         && String.Equals (u.State, a.State, StringComparison.OrdinalIgnoreCase) 
         && String.Equals (u.ZipCode, a.Zip, StringComparison.OrdinalIgnoreCase) 
       select a; 

雖然如果你的數據庫已經是不區分大小寫的,這取決於如何LINQ到SQL分裂SQL和C#代碼之間的工作,你可能不需要在all--不靈敏檢查雖然如果是我,我寧願保證安全,並確保您始終執行案件檢查。

+0

String.Equals似乎不適用於Linq-to-SQL。您將得到以下異常:「NotSupportedException:Method'布爾等於(System.String,System.String,System.StringComparison)'不支持對SQL的轉換。」我也嘗試使用String.IsNullOrEmpty()作爲空檢查,但我得到了相同的錯誤信息 –

+0

看看我的修訂答案 - 你得到的錯誤信息是一個好兆頭,這意味着解決方案可能更容易! :-) –

+1

謝謝!這工作。真正有趣的是在查看生成的SQL查詢之後,String.Equals()生成的查詢類似於我原先沒有使用ToLower()方法調用的查詢。基本上,它檢查不爲空,然後檢查是否相等。所以只需使用u.Street_address == a.Street1是不夠的,你還必須檢查null。我相信那是因爲SQL不能使用=來比較NULL。我不明白的是爲什麼==不被評估爲String.Equals()? –

相關問題