我一直在努力解决这个问题,似乎无法弄清楚......
我有一个BlogPost
课程,其中包含Comments
个集合,每个评论都有一个DatePosted
字段。
我需要做的是查询BlogPost
并使用部分加载的Comments
集合返回它,比如2009年8月1日发布的所有评论。
我有这个问题:
BlogPost post = session.CreateCriteria<BlogPost>()
.Add(Restrictions.Eq("Id", 1))
.CreateAlias("Comments", "c")
.Add(Restrictions.Eq("c.DatePosted", new DateTime(2009, 8, 1)))
.UniqueResult<BlogPost>();
当我运行此查询并检出生成的sql时,它首先针对BlogPost
表运行查询,使用正确的日期限制加入Comment
表,然后运行第二个查询就在返回所有内容的Comment
表上。
结果是Comments
类的BlogPost
集合完全填满了!
我做错了什么?
如果有人需要更多信息,我会收到代码示例......
答案 0 :(得分:2)
有一个结果转换器,请参阅the documentation.
引用:
请注意小猫收藏品 由Cat返回的实例 前两个查询不是 按标准预过滤!如果你 希望只检索那只小猫 符合标准,你必须使用
SetResultTransformer(CriteriaUtil.AliasToEntityMap)
。IList cats = sess.CreateCriteria(typeof(Cat)) .CreateCriteria("Kittens", "kt") .Add( Expression.Eq("Name", "F%") ) .SetResultTransformer(CriteriaUtil.AliasToEntityMap) .List();
您还可以使用session.EnableFilter(name)
激活的过滤器。
答案 1 :(得分:0)
你真的没有做错任何事 - hibernate就是这样不行。
如果您从BlogPost导航到评论,Hibernate将根据您指定的关联映射填充注释,而不是您用于检索BlogPost的查询。据推测,您的映射只是在进行连接 在关键栏目上。您可以使用您正在寻找的filter to get the effect。但我认为仍然可以获取所有评论,然后进行后期过滤。
更简单地说,只需查询您想要的内容:
List<Comments> comments = session.CreateCriteria<BlogPost>()
.Add(Restrictions.Eq("Id", 1))
.CreateAlias("Comments", "c")
.Add(Restrictions.Eq("c.DatePosted", new DateTime(2009, 8, 1)))
.list();
这实际上只返回指定日期的评论。 如果它让你感觉更好,你可以这样设置它们:
post.setComments(comments); //having already retreived the post elsewhere
当我第一次遇到它时,我也对这种行为感到惊讶。这似乎是一个错误,但我已经被告知它的设计。
答案 2 :(得分:0)
感谢您的回复,我想我有点理解为什么它的设计,但我会想到会有一个内置的方法来启用它,你的解决方案有效,但感觉有点像黑客!
我的问题是,如果没有过滤,子集合是巨大的(我给出的帖子和评论的例子是为了保护无辜的名字!)现在我可以每次都将所有数据拉回来。
我在这上面运行了Sql Profiler,它仍然将所有数据都拉回来。 当我运行以下代码时,第一个查询执行您所期望的,只有一个帖子返回,但是一旦执行第二个查询,两个查询将转到数据库,第一个检索过滤的注释(bingo!),然后第二个用所有评论填充post.Comments属性,正是我想避免的!
var post = session.CreateCriteria<BlogPost>()
.Add(Restrictions.Eq("Id", 1))
.UniqueResult<BlogPost>();
var comments = session.CreateCriteria<Comment>()
.Add(Restrictions.Eq("BlogPostId", 1))
.Add(Restrictions.Eq("DatePosted", new DateTime(2009, 8, 1)))
.List<Comment>();
post.Comments = comments;
这很奇怪,它不像我在post.Comments列表中列举,所以为什么要填充它?!这是我的课程和地图:
public class BlogPostMap : ClassMap<BlogPost>
{
public BlogPostMap()
{
Id(b => b.Id);
Map(b => b.Title);
Map(b => b.Body);
HasMany(b => b.Comments).KeyColumnNames.Add("BlogPostId");
}
}
public class CommentMap : ClassMap<Comment>
{
public CommentMap()
{
Id(c => c.Id);
Map(c => c.BlogPostId);
Map(c => c.Text);
Map(c => c.DatePosted);
}
}
public class BlogPost
{
public virtual int Id { get; set; }
public virtual string Title { get; set; }
public virtual string Body { get; set; }
public virtual IList<Comment> Comments { get; set; }
}
public class Comment
{
public virtual int Id { get; set; }
public virtual int BlogPostId { get; set; }
public virtual string Text { get; set; }
public virtual DateTime DatePosted { get; set; }
}
任何想法?
答案 3 :(得分:0)
我同意手动填充该集合感觉就像是一个黑客。
您可以改用自定义加载程序。像这样:
<query name="loadComments">
<return alias="comments" class="Comment"/>
<load-collection alias="comments" role="Post.comments"/>
from Comments c where c.Id = ? and c.DatePosted = SYSDATE
</query>
此外,如果您想要更多控制,可以使用sql-query。 当我无法通过hibernate生成我想要的查询时,我偶尔会弯腰编写自定义加载器。无论如何,不知道为什么我一开始就没有想到这一点。
答案 4 :(得分:0)
使评论集合变得懒惰,以便当您获得BlogPost时,hibernate不会获取它。然后在Comments集合上使用过滤器。
comments = session.CreateFilter(blogPost.Comments, ... ).List();