具有null值的LINQ to SQL
本文关键字:to SQL LINQ 值的 null 具有 | 更新日期: 2023-09-27 18:22:23
有人能帮我弄清楚吗?
以下代码运行良好,并进入if状态
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;
我对这个有点困惑,但我有一个疯狂的猜测。如果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
,因为当您重新计算msg
序列时(在上面的情况下,当您执行msg.Any
时,它会向数据库发出EXISTS
命令),您对m.PhoneNumber
的分配将丢失。
为了保留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
上的任何后续查询都将根据预先填充的内存集合(其中包含您分配给其元素的任何新值)进行评估。