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());