我一直在尝试过滤一些子对象的集合几个小时,并且终于举手了!我是NHibernate的新手,并且希望对此提出几点建议。我已经尝试了各种ICriteria等没有运气。我只是没有得到它。
我有一个父对象'Post',其中包含一组子对象'Comment'。该集合在Comment侧被映射为带反转的集合。
我要做的是只返回状态枚举值为“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; }
}
我的检索代码目前看起来像这样:
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来过滤我想要的评论。然而,问题仍然存在,即使只是从学术角度来看。
我已将选择更新为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,我没有发帖。
任何?我现在难过了!
更新:感谢所有回复的人,这很有用,并迫使我重新评估部分模型。由于最常使用评论作为帖子的子项是在查看帖子时,因此在此方案中只能查看已批准的评论。在大多数其他情况下,我可以想到评论将被直接访问并按状态过滤,这当然是直接的。
我已更新我的映射以过滤所有帖子&gt;注释加载仅按如下方式加载已批准的帖子(在FluentNHibernate中):
HasMany(x => x.Comments).Where(x => x.Status == CommentStatus.Approved)
.AsSet()
.Inverse()
.KeyColumn("PostId")
.ForeignKeyConstraintName("PostComments")
.OrderBy("CreatedOn")
.Cascade.AllDeleteOrphan();
我希望我能把所有人都标记为答案,因为所有这些都有助于我解决这个问题,但彼得是第一个指出我可能不正确地考虑模型的人。
感谢所有人。
答案 0 :(得分:0)
据我所知,SQL非常适合您描述的内容。
数据库有自己的优化器,并且知道如何使您的数据有效地传递到您的家门口。
答案 1 :(得分:0)
我认为这样可行:
var comments =
_session.CreateCriteria<Comment>
.CreateAlias("Post", "post")
.Add (Restriction.Eq("Status", status))
.Add (Restriction.Eq("post.Id", Id)).List();
如果您需要.CreateAlias部分(如果您不需要它,也许Post.Id也会起作用 - 但我不确定),我不是不舒服。
答案 2 :(得分:0)
我会使用IEnumerable<Comment>
的扩展方法解决这个问题:
public static IEnumerable<Comment> FilterByStatus(this IEnumerable<Comment> comments, CommentStatus status)
{
return comments.Where(x => x.Status == status);
}
让NHibernate返回整个集合,然后根据需要对其进行过滤。