Hibernate Criteria API – 过滤集合属性

我有这样的实体:

@Entity public class Album { private Integer id; private Integer ownerId; private String name; private String description; private Date created; @OneToMany @JoinColumn(name = "albumId") private Set users = new HashSet(); @OneToMany @JoinColumn(name = "albumId") private Set pictures = new HashSet(); } 

另一个:

 @Entity public class Picture { private Integer id; private Integer creatorId; private Integer albumId; private Date created; private String title; private String description; @ManyToOne @JoinColumn(name = "eventId") private Event event; } 

使用Criteria API我希望获得具有过滤的Picturs集的唯一AlbumD。 我尝试这样的事情:

 public Album read(Integer albumId, Set picFilter) { Criteria crit = getCurrentSession().createCriteria(Album.class, "album"); crit.add(Restrictions.idEq(albumId)); if (picFilter != null && !picFilter.isEmpty()) { crit = crit.createAlias("album.pictures", "picture"); crit.add(Restrictions.in("picture.event.id", picFilter)); crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); } Album resultDs = (Album) crit.uniqueResult(); return resultDs; } 

在这里,我得到所有相关图片的相册。 他们根本没有过滤。 当我尝试执行由记录器打印的查询时,我只得到四行,即给定eventId的图片数量,但在相册中我得到所有图片。

我也尝试了其他的ResultTransformers,但最终得到了很多结果(4)并不是一个明显的结果。

我错过了什么或做错了什么?

您不能通过在查询中包含对集合的限制来过滤与实体关联的集合的内容。 查询将仅获取相册。 访问Collection时,可以稍后获取Collection的内容。 您所做的只是过滤相册以仅检索包含带有事件ID的图片的相册。

如果Collection只包含与您的Criteria匹配的图片,并且您将获得部分Collection,则会导致更新问题,因为Hibernate认为已过滤的项目已被删除并会更新数据库以反映该更改,实际上删除了项目来自collections。

如果您只想从Collection中接收一些项目,可以使用Session.createFilter()方法。 唯一的问题是,它目前只支持HQL查询。

我记得这是我最近做的事情的一个问题。 你试过这个:

 if (picFilter != null && !picFilter.isEmpty()) { Criteria subCriteria = crit.createCriteria("album.pictures"); // Or just 'pictures?' Disjunction or = Restrictions.disjunction(); for (Integer id : picFilter) or.add(Restrictions.idEq(id)); subCriteria.add(or); crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); } 

尝试这个:

  Criteria crit = getCurrentSession().createCriteria(Album.class, "album"); crit.add(Restrictions.idEq(albumId)); if (picFilter != null && !picFilter.isEmpty()) { crit.createAlias("album.pictures", "picture"); crit.createAlias("picture.event", "event"); crit.add(Restrictions.in("event.id", picFilter)); crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); } 

如果在left_join中使用别名,则只返回满足相关条件的子对象。 否则它返回满足条件但具有所有子对象集的主对象。

 crit = crit.createAlias("album.pictures", "picture", CriteriaSpecification.LEFT_JOIN); 

这个方法在一些hibernate版本中被删除了,如果是这样你也可以使用下面的解决方案: 带有过滤复杂集的条件