我有一个相当丑陋的服务工作,它通过遗留数据库运行并将其与我们的生产数据库进行比较:
if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null) {
var oldDbContractItem = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).First();
// check to see if there were changes
if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
{
oldDbContractItem.Update(vendorContractItem);
}
}
我会在var oldDbContratItem
上收到错误,“Sequence不包含任何元素”,但我只是做了一个!= null检查。这一定很简单,发生了什么?
答案 0 :(得分:17)
如果我能教人们关于LINQ的一件事就是:查询表达式的值是表示查询的对象,而不是查询的结果 。从根本上说这是你的问题;您将查询视为其结果。查询不仅仅是餐厅是俱乐部三明治的结果。餐厅是生产俱乐部三明治的设备;查询是产生结果的设备。
答案 1 :(得分:7)
这是对你正在做的null
的测试:
vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null
总是是真的;这将至少返回一个空序列......永远不会是null
。
您可能有意测试其长度是否大于0?
然而,有一种更简单的方法,IMO。请致电FirstOrDefault()
而不是First()
,并完全省略预测试。然后,测试FirstOrDefault()
的结果是否为null
。
var oldDbContractItem = vendorContract.Item
.Where(x => x.ItemNumber == contractItem.Item_Number).FirstOrDefault();
if(oldDbContractItem != null) //would be null if there are no items
{
// check to see if there were changes
if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
{
oldDbContractItem.Update(vendorContractItem);
}
}
}
答案 2 :(得分:2)
因为你的查询返回了一个容器,所以它恰好是空的,返回的空检查不是返回包含的内容。
试试这个......
if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).Any())
{
.....
}
答案 3 :(得分:1)
不要运行查询两次。它效率低下,可能会在您的代码中引入竞争条件。此外,直接使用IEnumerator<T>
或使用foreach
循环可以更好地支持您的逻辑。
使用:
var result = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).GetEnumerator();
if (result.MoveNext) {
var oldDbContractItem = result.Current;
// ...
}
或
foreach (var oldDbContractItem in vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number)) {
// ...
break;
}
答案 4 :(得分:0)
使用已接受答案中的修复程序后,您可以使用以下步骤进一步调试LINQ情况(如果需要)。 LINQ是一项令人兴奋的技术,但需要一段时间来解决它的问题 - 我想说的是一种范式转换。 Eric's answer击中头部,因为他可能帮助建造了这些东西!
LINQ的调试步骤
要处理第二个语句没有结果的问题,请将.First()
更改为.FirstOrDefault()
如果未找到任何结果,则会返回数据类型的默认值 - 如果数据类型为一个类,它将返回一个空值。然后,您的第二个语句也应该使用空检查而且没有错误。
然后你可以调试你的LINQ语句,找出它正在做的事情。
如果使用LINQ to SQL,Visual Studio 2010中的Intellisense将显示将鼠标悬停在查询变量上时生成的SQL(不是查询结果)。如果您需要VS 2008 it's here
类似地,如果您使用的是LINQ to Entity Framework,则可以使用visualizer plugin here获取生成的SQL。
我总是从这些工具中获取生成的SQL,将其直接粘贴到查询窗口并在那里运行。它将显示您正在返回的空集,如果这是一个问题,您可以通过这种可视化生成的语句的方式进一步调试它。
答案 5 :(得分:0)
没有元素的序列仍然是一个对象。
答案 6 :(得分:0)
Where
可以返回非null值,但仍然可以解析为不包含元素的序列。在您的失败声明中,您正在使用其他内容,即Where().First()
。如果来自Where
的序列确实为空,那将为null。
答案 7 :(得分:0)
null
与空序列(例如类似new List<T>()
之类的内容)之间存在差异。您要做的是使用Any()
检查序列是否包含任何元素,或者将First()
替换为FirstOrDefault()
,如果序列不包含任何元素,则返回null
。 (如果您使用它,请确保null
不是First()
)可能返回的有效值。