2012-02-04 70 views
3

任何人都可以幫我弄清楚這一點嗎?LINQ to SQL與NULL值

下面的代碼工作正常,並得到裏面的,如果statument

foreach (var m in msg) 
{ 
    if (string.IsNullOrEmpty(m.PhoneNumber)) 
    { 
     m.PhoneNumber = (from c in db.Customers 
          where c.CustomerID == m.CustomerID 
          select c.PhoneNumber).Single(); 
    } 
} 

然而,在下面的代碼phoneNumber的是從來沒有設置

foreach (var m in msg.Where(z => (z.PhoneNumber == null || z.PhoneNumber == ""))) 
{ 
    m.PhoneNumber = (from c in db.Customers 
         where c.CustomerID == m.CustomerID 
         select c.PhoneNumber).Single(); 
} 

我假定它是因爲頂部代碼實際上評估表達而下面的劑量。如果是這種情況,那麼如何在未評估的LINQ查詢中檢查null?

編輯只是要停在這裏的困惑是味精是如何在這兩種情況下

var msg = from m in db.Messages 
       where (m.StatusID == (int)MessageStatus.Submitted && m.MessageBoxTypeID == (int)MessageBoxType.Outbox) 
       select m; 
+0

您是否在創建'msg'序列時使用了相同的代碼? (這兩個片段看起來相當於我,除非我失去了一些東西。) – Douglas 2012-02-04 13:50:16

+0

是的,味精是完全一樣的 – 2012-02-04 13:53:14

+0

你能告訴我們'味精'的代碼嗎? – Douglas 2012-02-04 13:59:05

回答

1

我有點被這莫名其妙一個poplated,但我有一個胡亂猜測。如果msg序列是轉換爲SQL查詢的IQueryable<T>,那麼這兩個片段的行爲可能會有所不同。假設你有:

var msg = 
    from m in dataContext.MyTable 
    select m; 

你的第一個片段會導致出現以下列舉整個msg序列,從而發出一個未經過濾的SELECT…FROM命令將數據庫和表中提取所有行。

foreach (var m in msg) 

在另一方面,你的第二個片段將過濾器應用於您的序列之前將其一一列舉。因此,發佈到數據庫的命令是SELECT…FROM…WHERE

foreach (var m in msg.Where(z => (z.PhoneNumber == null || z.PhoneNumber == ""))) 

有很多情況下,在.NET中應用的過濾器的行爲與Transact-SQL的轉換有所不同。例如,區分大小寫。在你的情況下,我認爲這個不匹配是由PhoneNumber由空白組成的條目引起的,因爲它們可能與SQL Server中的空字符串相匹配。

爲了測試這種可能性,檢查,如果你改變你的第二個片段會發生什麼:

foreach (var m in msg.ToList().Where(z => (z.PhoneNumber == null || z.PhoneNumber == ""))) 

編輯:你的問題可能是要進行後續訪問期間再次執行查詢(當您檢查是否設置了PhoneNumber)。

如果執行:

foreach (var m in msg.Where(z => (z.PhoneNumber == null || z.PhoneNumber == ""))) 
{ 
    m.PhoneNumber = … 
} 

bool stillHasNulls = msg.Any(z => z.PhoneNumber == null || z.PhoneNumber == ""); 

你會發現,stillHasNulls可能仍計算爲true,因爲你的分配m.PhoneNumber正在消失,當你重新評估msg序列(在上述情況下,當你執行msg.Any,它向數據庫發出一個EXISTS命令)。

爲了讓您的m.PhoneNumber保留指定,您需要將它們保存到數據庫(如果這是您想要的),或者確保您每次都訪問相同的序列元素。一種方法是使用ToList將序列預填充爲集合。

msg = msg.Where(z => (z.PhoneNumber == null || z.PhoneNumber == "")).ToList(); 
foreach (var m in msg) 
{ 
    m.PhoneNumber = … 
} 

在上面的代碼中,過濾器仍然得到向數據庫發出的作爲SELECT…FROM…WHERE,但結果是熱切評價,然後存儲爲內msg列表。對msg的任何後續查詢都將根據預填充的內存集合(其中將包含您分配給其元素的任何新值)進行評估。

+0

ToList()會評估這個陳述並且會工作(與第二個snippit相同,我更想知道如何在不評估表達式的情況下檢查是否爲空) – 2012-02-04 14:24:20

+0

如何檢查是否設置了PhoneNumber?在你的賦值語句中設置一個斷點,或者你是否在循環中檢查'msg'的元素的值? – Douglas 2012-02-04 14:30:12

+0

如果你只是想檢查'null'作爲查詢的一部分(沒有急切的評估),那麼你的第二個代碼片段是正確的。 – Douglas 2012-02-04 14:31:25