【问题标题】:NHibernate 3.0: No FirstOrDefault() with QueryOver?NHibernate 3.0:QueryOver 没有 FirstOrDefault()?
【发布时间】:2010-12-29 13:23:49
【问题描述】:

我正在使用 FluentNHibernate 和 NH 3.0,使用 LINQ 提供程序和新的 QueryOver 语法。

现在使用 QueryOver 我想获得一个时间戳值尽可能接近给定值但不大于给定值的项目(称为结果):

 Result precedingOrMatchingResult = Session.QueryOver<Result>().
        Where(r => r.TimeStamp < timeStamp).
        OrderBy(r => r.TimeStamp).Desc.                
        FirstOrDefault(); //get the preceding or matching result, if there is any

现在,Intellisense 告诉我没有 FirstOrDefault() 方法这样的东西。当然,我可以枚举我的有序查询,然后使用 LINQ 来获取我的项目。但这会首先将所有项目加载到内存中。

是否有替代 FirstOrDefault() 的方法,或者我完全理解错误?

【问题讨论】:

  • 寻找SingleOrDefault()。请接受@RRR 的回答。

标签: linq nhibernate linq-to-nhibernate queryover


【解决方案1】:

我现在发现我可以在 IQueryOver 实例上使用 Take() 扩展方法,并且只对列表进行枚举,如下所示:

Result precedingOrMatchingResult = Session.QueryOver<Result>().
        Where(r => r.TimeStamp < timeStamp).
        OrderBy(r => r.TimeStamp).Desc.   
        Take(1).List(). //enumerate only on element of the sequence!
        FirstOrDefault(); //get the preceding or matching result, if there is any

【讨论】:

  • 是的。 Take 是我要推荐的。将它与 RRR 的 SingleOrDefault 而不是 List().FirstOrDefault() 结合起来,就完美了。
  • 实际上.Take(1) 会和.SetFetchSize(1) 做同样的事情,因为它会告诉SQL 你只想要一个结果。在这两种情况下,您都没有对所有匹配结果执行查询,然后枚举第一个。
  • 只是想提一下评论中有错字。 '仅枚举' -> '仅枚举一个'。很好的答案。
【解决方案2】:
Result precedingOrMatchingResult = Session.QueryOver<Result>()
                                          .Where(r => r.TimeStamp < timeStamp)
                                          .OrderBy(r => r.TimeStamp).Desc
                                          .SingleOrDefault();

【讨论】:

  • 导致 NHibernate.NonUniqueResultException
  • 在这种情况下,在.SingleOrDefault() 之前尝试.Take(1)。请参阅@Marcel 的回答。
  • 这不是正确的答案。如果有多个结果,SingleOrDefault 会引发异常。 FirstOrDefault 没有。但是,您可以尝试 .Take(1).SingleOrDefault()
  • @wezzix 这是一个很好的观点,但是 OP 表示不需要特殊行为 - 看起来他不知道或不关心它 - 他只是要求一个电话替代枚举所有内容并获得第一名
  • @PandaWood 不,OP 正在排序并希望获得最高结果,因此 SingleOrDefault 不回答问题(单独)。
【解决方案3】:

NH 3 具有集成的 LINQ 提供程序(查询在内部转换为 HQL/SQL)。您必须添加 NHibernate.Linq 命名空间,然后:

Result precedingOrMatchingResult = Session.Query<Result>().
    Where(r => r.TimeStamp < timeStamp).
    OrderByDescending(r => r.TimeStamp).
    FirstOrDefault();

【讨论】:

  • 看起来不错,我会试一试(不过只有明年,因为我现在不在!)
  • 这可以解决问题。但是,由于在我的 Where 子句中有一些额外的限制,我发现 LINQ to NH 不支持 Nullable 类型的 .HasValue() 方法支持。太糟糕了,但我现在检查 != null 是否有效。
  • 这并没有回答使用 QueryOver 执行此操作的问题。答案是有效的,只是不适用于所提出的问题。 @RRR 更正确。
【解决方案4】:

试试

Result precedingOrMatchingResult = Session.QueryOver<Result>().
        Where(r => r.TimeStamp < timeStamp).
        OrderBy(r => r.TimeStamp).Desc.
        SetFetchSize(1).
        UniqueResult();

UniqueResult 将返回单个值,如果没有找到值,则返回 null,这有点像 First 或 Default 所做的。

可能需要也可能不需要将 Fetch Size 设置为 1,我会使用分析器对其进行测试。

【讨论】:

  • 我看过了。 UniqueResult 似乎类似于 SingleOrDefault,但我没有一个项目。我有一个列表,我只想选择第一项。
  • 您希望查询返回的只是第一项,对吗?为什么要从数据库服务器返回一个列表,然后丢掉大部分工作?
【解决方案5】:

SetFetchSize(1) 是必需的。如果您的 LINQ 查询返回多个结果,它将使用UniqueResult() 引发 NHibernate 异常,因为它只期望从查询返回一个结果。

【讨论】:

  • 欢迎来到 Stack Overflow 并感谢您的贡献!您的答案似乎与问题没有 100% 相关,因为问题中没有提到 SetFetchSize。也许你可以解释得更清楚或更正确。我们的指南How to write a good answer 可能会给您有用的提示。谢谢!
  • 嗨大卫,我的意思是评论我上面的答案,而不是提供一个全新的答案。我的错。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多