【问题标题】:How do I rewrite this Linq query to avoid using FirstOrDefault?如何重写此 Linq 查询以避免使用 FirstOrDefault?
【发布时间】:2017-02-21 04:39:53
【问题描述】:

我有一个 Quotes 表,它有一个关联的 Revisions 表。一个基本的业务规则是报价必须至少有一个修订版,但可能有很多。我有一个这样开头的查询...

var revisions = ctx.Quotes
  .Select(q => q.Revisions.OrderByDescending(r => r.RevisionNumber).FirstOrDefault())
  // Do things with the revisions here...

目的是获取每个报价的最新版本,然后从中选择一些信息。

这工作正常,除了我们在数据库中有一个没有任何修订的流氓报价。在上面显示的代码下方的某个地方,我遇到了一个异常......

转换为值类型“System.Int32”失败,因为物化了 值为空。结果类型的泛型参数或查询 必须使用可空类型

调试需要很长时间,因为我们没有意识到这是由流氓引用引起的。理想情况下,查询的第二行将使用 First() 而不是 FirstOrDefault(),这会在此处引发异常,立即显示问题的根源。但是,Entity Framework 不允许您使用 First() 或 Single() 中间查询,这就是我们使用 FirstOrDefault() 的原因。

如果不完全重写查询,即首先查询 Revisions 表并导航回 Quote(由于其他原因会很痛苦),是否有一种简单的方法来防止这种情况发生?在这种情况下,我通过将第一行更改为...来修复它。

var revisions = ctx.Quotes.Where(q => q.Revisions.Any())

...但这是针对这种情况的特定修复,并且仅在我们最终发现问题后才明显。理想情况下,我想要一个普遍适用的解决方案。

【问题讨论】:

  • 您显示的查询部分似乎很好。知道它是如何进行的会很有趣。怀疑您将生成的修订版投影到提取整数的东西中。请提供整个查询。
  • @tinudu 正如我解释的那样,我展示的查询部分是问题所在,因为它假设每个报价都有一个修订版(它应该有),并且 FirstOrDefault() 是返回默认值,导致问题降低。不管后面发生了什么,我什么都做不了,只要查询有要枚举的东西,它就会抛出异常

标签: c# entity-framework linq


【解决方案1】:

为了获得内连接语义,IMO 将Select / OrderBy / FirstOrDefault 的一般替换为SelectMany / OrderBy / Take(1)

var revisions = ctx.Quotes
    .SelectMany(q => q.Revisions.OrderByDescending(r => r.RevisionNumber).Take(1))
    // Do things with the revisions here...

【讨论】:

  • Brilliaint,如此明显而简单的方法。让我想知道为什么微软觉得他们无法在 EF 中实现 First(),而它与他们实现的 Take(1) 相同。感谢您的回复。
猜你喜欢
  • 2017-02-09
  • 1970-01-01
  • 2015-08-27
  • 1970-01-01
  • 2013-09-25
  • 1970-01-01
  • 1970-01-01
  • 2011-09-10
  • 1970-01-01
相关资源
最近更新 更多