NHibernate LinqProvider / IQueryable:在 Where 子句中是不是支持 FirstOrDefault()?

Posted

技术标签:

【中文标题】NHibernate LinqProvider / IQueryable:在 Where 子句中是不是支持 FirstOrDefault()?【英文标题】:NHibernate LinqProvider / IQueryable: Is FirstOrDefault() supported inside a Where clause?NHibernate LinqProvider / IQueryable:在 Where 子句中是否支持 FirstOrDefault()? 【发布时间】:2012-10-09 14:50:29 【问题描述】:

给定两个相似的类

public class Blog

    public virtual int BlogId  get; set; 
    public virtual IList<Comment> Comments  get; set; 


public class Comment

    public virtual int CommentId  get; set; 
    public virtual Blog Blog  get; set; 
    public string Title  get; set; 

我很难使用以下语句:

session.Query<Blog>.Where(b => b.Comments.FirstOrDefault().Title.Contains("my title")));

抛出的错误是:

Antlr.Runtime.NoViableAltException

使用 .Any() 有效:

session.Query<Blog>.Where(b => b.Comments.Any(c => c.Title.Contains("my title")));

然而,这不是我想要的。实际上,这不是关于博客和评论,而是关于版本化实体。在它们的父实体的映射中,我按它们的版本号对它们的集合进行排序。我需要能够访问第一个条目才能获得最新版本。

【问题讨论】:

不支持因为FirstOrDefault()ToList() 等方法,它们将 IQueryable 完成为具体类型(原始类型、唯一实体和列表)。如果你调用这样的东西,你会得到一个异常,因为你仍然在执行的上下文中,是什么让你无法运行子查询。在这种情况下,您必须使用.Any 方法,因为它会在 SQL 语句内部生成一个子选择。 为了解决您的问题,您可以在您的存储库中添加一个方法来获取第一个带有 idBlog 的评论。 @Felipe Orani:这是复杂查询的一部分,为每个博客触发选择不会很好。一个技巧是将 FirstCommentId 属性添加到实体 Blog 并通过公式映射该属性(“Select Top 1 CommentId from ...”),然后执行 .Any(c=> c.CommentId == b.FirstCommentId && c.Title.Contains("我的标题") 【参考方案1】:

为什么不在 db 中预过滤并使用 linq to objects 最终过滤它?

var results = session.Query<Blog>()
    .Where(b => b.Comments.Any(c => c.Title.Contains("my title")))
    .AsEnumerable()
    .Where(b => b.Comments[0].Title.Contains("my title")))
    .ToList();

或者如果列表位置在评论中(不漂亮)

Map(x => x.Position, "listindexcolumn").ReadOnly();

var results = session.Query<Blog>()
    .Where(b => b.Comments.Any(c => c.Position == 0 && c.Title.Contains("my title")))
    .ToList();

或使用仅查询属性

Map(x => this.Position, "listindexcolumn").ReadOnly().Access.None();

var results = session.CreateCriteria<Blog>()
    .CreateCriteria("Comments")
        .Add(Restriction.Eq("Position", 0) && Restriction.Like("Title", "my title"))
    .ToList<Blog>();

【讨论】:

以上是关于NHibernate LinqProvider / IQueryable:在 Where 子句中是不是支持 FirstOrDefault()?的主要内容,如果未能解决你的问题,请参考以下文章

Nhibernate学习教程-- 第一个NHibernate程序

NHibernate教程(19) —— 一级缓存

Nhibernate学习教程-- 开篇有益

NHibernate 2 + NHibernate.JetDriver + MS Access:如何访问表的“附件”字段

NHibernate3剖析:Query篇之NHibernate.Linq增强查询

Linq几样特点