LINQ 失败了吗?
LINQ Any failing?
以下代码中的 Any
函数会失败吗?
var orders = db.Order.Where(order => order.Item.Any());
foreach (var order in orders)
{
var first = order.Item.First(); // NullReferenceException thrown here: order.Item == null
}
也许我只是误解了这里的某些东西,但在我看来 order.Item
应该永远不会为空,因为之前的 Any
声明。
编辑:如果我通过在此处放置 ToList
来确保表达式已被求值而不是延迟,则由于 order.Item
序列没有任何项目,我会得到另一个异常,这也让我感到困惑:
var orders = db.Order.Where(order => order.Item.Any()).ToList();
foreach (var order in orders)
{
var first = order.Item.First(); // System.InvalidOperationException thrown here: order.Item.Count == 0
}
计算orders
的表达式是延迟的,所以当db.Order
的[=16=中有任何null
时], 直到进入 foreach
循环才能找到它们。
您可以通过添加 ToList()
调用来查看发生了什么:
var orders = db.Order.Where(order => order.Item.Any()).ToList();
现在异常将在循环之前抛出。
您可以通过在 Where
条件中添加显式 null
检查或使用 C# 6 的新 ?.
语法来解决此问题:
var orders = db.Order.Where(order => order.Item != null && order.Item.Any());
或
var orders = db.Order.Where(order => order?.Item.Any());
order.Item.Count == 0
错误可能具有相同的性质:由于对 Any()
的检查是在数据库级别完成的,而对 First()
的调用发生在稍后的某个时间,有可能 Any()
成功的项目在您调用 First()
.
时已经消失
您应该可以通过为 Item
添加 LoadWith
选项来解决此问题。
这一行:
var orders = db.Order.Where(order => order.Item.Any());
只有在需要时才会实际求值,因此稍后似乎会失败。
如果您将此行替换为:
var orders = db.Order.Where(order => order.Item.Any()).ToList();
您会立即看到失败,因为在生成列表时会评估查询。
将行替换为:
var orders = db.Order.Where(order => order.Item != null && order.Item.Any());
它应该可以正常工作
它比你想象的要简单。
根据 definition of Enumerable.Any,如果 source 为空,则抛出 ArgumentNullException。
您的 class 订单有一个 属性 Order.Item。您的一个订单有一个值为 null 的项目。您的代码应该是:
var orders = db.Order.Where(order => order.Item != null && order.Item.Any());
以下代码中的 Any
函数会失败吗?
var orders = db.Order.Where(order => order.Item.Any());
foreach (var order in orders)
{
var first = order.Item.First(); // NullReferenceException thrown here: order.Item == null
}
也许我只是误解了这里的某些东西,但在我看来 order.Item
应该永远不会为空,因为之前的 Any
声明。
编辑:如果我通过在此处放置 ToList
来确保表达式已被求值而不是延迟,则由于 order.Item
序列没有任何项目,我会得到另一个异常,这也让我感到困惑:
var orders = db.Order.Where(order => order.Item.Any()).ToList();
foreach (var order in orders)
{
var first = order.Item.First(); // System.InvalidOperationException thrown here: order.Item.Count == 0
}
计算orders
的表达式是延迟的,所以当db.Order
的[=16=中有任何null
时], 直到进入 foreach
循环才能找到它们。
您可以通过添加 ToList()
调用来查看发生了什么:
var orders = db.Order.Where(order => order.Item.Any()).ToList();
现在异常将在循环之前抛出。
您可以通过在 Where
条件中添加显式 null
检查或使用 C# 6 的新 ?.
语法来解决此问题:
var orders = db.Order.Where(order => order.Item != null && order.Item.Any());
或
var orders = db.Order.Where(order => order?.Item.Any());
order.Item.Count == 0
错误可能具有相同的性质:由于对 Any()
的检查是在数据库级别完成的,而对 First()
的调用发生在稍后的某个时间,有可能 Any()
成功的项目在您调用 First()
.
您应该可以通过为 Item
添加 LoadWith
选项来解决此问题。
这一行:
var orders = db.Order.Where(order => order.Item.Any());
只有在需要时才会实际求值,因此稍后似乎会失败。
如果您将此行替换为:
var orders = db.Order.Where(order => order.Item.Any()).ToList();
您会立即看到失败,因为在生成列表时会评估查询。
将行替换为:
var orders = db.Order.Where(order => order.Item != null && order.Item.Any());
它应该可以正常工作
它比你想象的要简单。 根据 definition of Enumerable.Any,如果 source 为空,则抛出 ArgumentNullException。
您的 class 订单有一个 属性 Order.Item。您的一个订单有一个值为 null 的项目。您的代码应该是:
var orders = db.Order.Where(order => order.Item != null && order.Item.Any());