【问题标题】:LINQ Any failing?LINQ 任何失败?
【发布时间】:2016-08-15 12:40:53
【问题描述】:

下面代码中的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
}

【问题讨论】:

  • order.Item 的类型是什么?
  • 它是Item,源自我模型中的Item 表。订单可以有 0 到 n 个项目
  • 你在使用EntityFramework吗?
  • “Item”不是一个结构,对吧?
  • @Adil:不,我的模型代码是使用 SQLMetal 生成的。

标签: c# linq any


【解决方案1】:

计算orders 的表达式是延迟的,所以当db.OrderItem 中有任何nulls 时,直到你在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() 的检查是在 DB 级别完成的,并且对 First() 的调用发生在稍后的某个时间,很可能是那里的项目Any() 的成功在您调用 First() 时已经消失。

您应该能够通过为Item 添加LoadWith 选项来解决此问题。

【讨论】:

  • 我认为这正是正在发生的事情,但这并不是完整的故事。我已经更新了我的问题,因为我仍然看不到 Any 可以如何执行,但是 order.Item 没有任何项目。
  • @Protectorone 我认为根本问题是相同的——检查和加载是在不同的时间执行的。你应该可以通过加载Item 来解决这个问题。
  • 使用DataLoadOptionsLoadWidth 确实解决了这个问题!我有什么办法可以事先预料到这个问题?我习惯于 LINQ 自动加载所需的任何实体……
  • @Protectorone 不幸的是,这是这些令人讨厌的情况之一,由于大量活动部件而很难预测错误。在某种程度上,此类问题更容易解决而不是预期。
【解决方案2】:

这一行:

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

它应该可以正常工作

【讨论】:

  • 这还不完全正确。如果我在我的代码中添加ToList,我已经用我收到的新异常更新了我的问题。
【解决方案3】:

它比你想象的要简单。 根据definition of Enumerable.Any,如果 source 为 null,则会引发 ArgumentNullException。

您的 Order 类有一个属性 Order.Item。您的一个订单有一个值为 null 的项目。你的代码应该是:

var orders = db.Order.Where(order => order.Item != null && order.Item.Any());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-01
    • 2017-03-31
    • 2017-06-18
    • 1970-01-01
    • 2020-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多