如何使用NHibernate通过属性有效地筛选子对象集合

如何使用NHibernate通过属性有效地筛选子对象集合,nhibernate,filtering,subquery,Nhibernate,Filtering,Subquery,几个小时以来,我一直在尝试过滤一组子对象,但都没有成功,最终还是举手了!我是NHibernate的新手,希望能在这方面得到一些建议。我尝试过各种各样的ICriteria等,但都没有成功。我就是不明白 我有一个父对象“Post”和一组子对象“Comment”。集合被映射为一个集合,在注释端使用inverse 我试图做的是只返回状态枚举值为“Comment.Approved”的注释 实体类别的相关部分如下所示: public class Post { public virtual Guid

几个小时以来,我一直在尝试过滤一组子对象,但都没有成功,最终还是举手了!我是NHibernate的新手,希望能在这方面得到一些建议。我尝试过各种各样的ICriteria等,但都没有成功。我就是不明白

我有一个父对象“Post”和一组子对象“Comment”。集合被映射为一个集合,在注释端使用inverse

我试图做的是只返回状态枚举值为“Comment.Approved”的注释

实体类别的相关部分如下所示:

public class Post
{
    public virtual Guid Id { get; protected set; }
    private ICollection<Comment> _comments;
    public virtual ICollection<Comment> Comments
    {
        get { return _comments; }
        protected set { _comments = value; }
    }
}

public class Comment
{
    public virtual Guid Id { get; protected set; }
    public virtual Post Post { get; set; }
    public virtual CommentStatus Status { get; set; }

 }
我已经在这里查看了与这类查询相关的各种答案,其中似乎没有一个能够解决这一特定场景

我可能错过了一些非常简单的东西,但我现在太累了,看不见了。我希望有更好的NHibernate的人能给我指出正确的方向

谢谢你抽出时间

编辑:仍在努力解决这个问题,这里的一些答案很好,因为我开始认为需要重新考虑我的帖子实体来执行过滤,或者我应该实现一个ViewModel来过滤我想要的评论。然而,这个问题仍然存在,即使只是从学术角度来看

我已将选择更新为HQL并尝试:

var post = _session
            .CreateQuery("select p from Post as p left join fetch p.Comments as c where p.Id = :id and c.Id in (select ac from p.Comments ac where ac.Status = :status)")
            .SetParameter("id", Id)
            .SetParameter("status", CommentStatus.Approved)
            .UniqueResult<Post>();
我希望我能把所有的都记下来作为答案,因为所有这些都有助于我解决这个问题,但彼得是第一个指出我可能对模型的想法不正确的人


感谢大家。

据我所知,SQL非常适合您所描述的内容


数据库有自己的优化器,它知道如何有效地将数据传送到您的家门口。

我认为这样做很好:

var comments =
_session.CreateCriteria<Comment>
.CreateAlias("Post", "post")
.Add (Restriction.Eq("Status", status))
.Add (Restriction.Eq("post.Id", Id)).List();
var注释=
_session.CreateCriteria
.CreateAlias(“Post”、“Post”)
.Add(Restriction.Eq(“状态”,Status))
.Add(Restriction.Eq(“post.Id”,Id)).List();

如果您需要.CreateAlias部分,我不是舒尔(如果您不需要,可能Post.Id也可以-但我不确定)。

我将使用扩展方法解决此问题,扩展方法为
IEnumerable

公共静态IEnumerable FilterByStatus(此IEnumerable comments,CommentStatus状态)
{
返回注释,其中(x=>x.Status==Status);
}

让NHibernate返回整个集合,然后根据需要对其进行过滤。

感谢您的注释,我希望Post对象具有一组经过过滤的注释,而不是在代码的其余部分使用第二个对象(var comments)。这可能只是我在行动中的保留力:)如果有一个替代方案允许我维护我的模型,我宁愿拥有它。我讨厌post对象仍然有我不想挂断的评论!这样做的危险在于,post对象中的“comments”字段在不同的情况下会有不同的含义,这很快就会变得复杂。考虑添加GETApvestDebug()或其他内容。通常,在一个请求中只需要一次这些东西,然后延迟加载将是有效的。如果你多次需要它们,你可以用这个方法缓存结果。嗯,这很有趣,我的知识还不足以让帕尔知道这一点,你能再解释一下吗。我理解你所说的评论的意思,我认为它们有不同的含义,即在这个例子中实际上是被批准的评论,在管理场景中可能是“垃圾邮件评论”、“不可靠的评论”和被批准的评论。您是否建议post对象应该有几个集合,每个集合都有不同的映射?我会在对象上或服务层中使用方法,具体取决于代码库中使用的约定。我不是svc.getApprovedMethods(post)或post.getApprovedMethods()的原教旨主义者。两人都“唱”出他们对我的意义。如果你喜欢瘦的东西,服务方式会更好,如果你不介意“胖”的东西,第二个会更自然。好的,你的评论是:具有新含义的评论真的让我思考-我什么时候才能作为帖子的孩子访问评论?不经常!可能只有在展示文章供查看时,这意味着90%的时间我们只需要获得批准的文章。我将更改映射以反映这一点。我知道您来自何处,但此查询仅返回注释。如果可能,我真正希望的是将带有其集合的post对象过滤到具有我正在查找状态的任何post。如果没有,我将不得不接受我所拥有的,但它似乎应该是直截了当的!在这种情况下,我将在Post类中创建一个属性,该属性将返回正确的注释(过滤注释属性),但这取决于您的应用程序(如果此“次优”查询可接受或不可接受),通常我将首先开始实现-然后测试-如果性能不好-我将开始优化这些情况(没有过早的优化)开始认为这或者bernhardrusch或Peter的其他方法可能是我唯一的选择。什么问题(除了好奇)你想解决这个问题吗?我猜评论在审核后会被批准。有效的评论总是会被批准;垃圾邮件或攻击性的评论会被删除。所以我希望绝大多数评论都会被批准。如果是这样的话,那么将它们全部返回可能更有效(选择FK)事实上,垃圾邮件评论不会被删除,因为它们将被用于贝叶斯过滤器中,以确定哪些是垃圾邮件,哪些不是垃圾邮件,所以我认为很有可能对一篇文章的所有评论进行选择,然后UI过滤会变得非常低效。但我还是不同意对此,我可能会说废话:你可能会考虑把垃圾邮件评论移到他们自己的桌子上,这样
var post = _session
            .CreateQuery("select p from Post as p left join fetch p.Comments as c where p.Id = :id and c.Id in (select ac from p.Comments ac where ac.Status = :status)")
            .SetParameter("id", Id)
            .SetParameter("status", CommentStatus.Approved)
            .UniqueResult<Post>();
 HasMany(x => x.Comments).Where(x => x.Status == CommentStatus.Approved)
            .AsSet()
            .Inverse()
            .KeyColumn("PostId")
            .ForeignKeyConstraintName("PostComments")
            .OrderBy("CreatedOn")
            .Cascade.AllDeleteOrphan();
var comments =
_session.CreateCriteria<Comment>
.CreateAlias("Post", "post")
.Add (Restriction.Eq("Status", status))
.Add (Restriction.Eq("post.Id", Id)).List();
public static IEnumerable<Comment> FilterByStatus(this IEnumerable<Comment> comments, CommentStatus status)
{
    return comments.Where(x => x.Status == status);
}