【发布时间】:2010-06-23 05:52:35
【问题描述】:
几个小时以来,我一直在尝试过滤一组子对象,但没有成功,我终于举手了!我是 NHibernate 的新手,并希望对此有一些指示。我尝试了各种 ICriteria 等,但都没有运气。我就是不明白。
我有一个父对象“发布”,其中包含一组子对象“评论”。该集合被映射为一个集合,在 Comment 端具有反转。
我要做的是只返回状态枚举值为“Comment.Approved”的 cmets
实体类的相关部分如下:
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; }
}
我现在的检索代码是这样的:
var Id = __SomeGuidHere__;
var post = _session
.CreateCriteria<Post>()
.Add(Restrictions.Eq("Id", Id))
.UniqueResult<Post>();
var comments = _session.CreateFilter(post.Comments, "where Status = :status").SetParameter("status", CommentStatus.Approved).List<Comment>();
虽然这样可行,但 SQL 似乎效率不高,但我希望能够将以下 SQL 转换为 HQL 或某种 ICriteria 中的类似内容:
SELECT * FROM posts p LEFT JOIN comments c ON p.PostId = c.PostId AND c.Status = 0 WHERE p.PostId = '66a2bf13-1330-4414-ac8a-9d9b00ea0705';
我在这里查看了与此类查询相关的各种答案,但似乎都没有解决这种特定情况。
这里可能缺少一些非常简单的东西,但我现在太累了,看不到它。希望有更好的 NHibernate 能够为我指明正确的方向。
感谢您的宝贵时间。
编辑:仍在为此苦苦挣扎,这里的一些答案很好,因为我开始认为我的帖子实体需要重新考虑以执行过滤本身,或者我应该实现一个 ViewModel 来过滤我想要的 cmets。但是,即使仅从学术角度来看,问题仍然存在。
我已将选择更新为 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>();
只要帖子有已获批准的评论,此方法就有效,否则由于在 where 子句中使用“AND”生成的 SQL,我没有收到任何帖子。
有人吗?我现在被难住了!
更新:感谢所有回复的人,它很有用,并迫使我重新评估我的模型的某些部分。由于最常使用 cmets 作为帖子的子项是在查看帖子时,因此在这种情况下应该只能查看已批准的 cmets。在我能想到的大多数其他场景中,cmets 将被直接访问并按状态过滤,这当然是直截了当的。
我已更新我的映射以过滤所有帖子 > 评论加载以仅加载已批准的帖子,如下所示(在 FluentNHibernate 中):
HasMany(x => x.Comments).Where(x => x.Status == CommentStatus.Approved)
.AsSet()
.Inverse()
.KeyColumn("PostId")
.ForeignKeyConstraintName("PostComments")
.OrderBy("CreatedOn")
.Cascade.AllDeleteOrphan();
我希望我可以将所有都标记为答案,因为所有这些都有助于我解决这个问题,但彼得是第一个指出我可能错误地考虑模型的人。
谢谢大家。
【问题讨论】:
-
你想解决什么问题(除了好奇心)?我的猜测是 cmets 在审核后获得批准。有效的 cmets 将始终获得批准;垃圾邮件或攻击性邮件将被删除。因此,我预计绝大多数 cmets 将获得批准。如果是这种情况,那么将它们全部返回(在 FK 上选择)并在 UI 中过滤可能比预先过滤它们更有效。
-
实际上垃圾邮件 cmets 不会被删除,因为它们将在贝叶斯过滤器中使用,以确定哪些是垃圾邮件,哪些不是将来,所以我认为很有可能为帖子选择所有 cmets,然后 UI 过滤可能会变得非常低效。
-
但是我又是新手,所以我可能会说垃圾:)
-
您可以考虑将垃圾邮件 cmets 移动到它们自己的表中,以便可以更轻松地将它们作为一组或在离线过程中进行分析。垃圾评论没有理由与帖子保持关联,您将节省为每个帖子过滤掉它们的开销。
标签: nhibernate filtering subquery