Hibernate Criteria API - 过滤集合属性

时间:2011-05-23 19:45:32

标签: java hibernate filtering criteria one-to-many

我有这样的实体:

@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<AlbumUser> users = new HashSet<AlbumUser>();
    @OneToMany @JoinColumn(name = "albumId")
    private Set<Picture> pictures = new HashSet<Picture>();
}

另一个:

@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<Integer> 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)并不是那么明显。

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

4 个答案:

答案 0 :(得分:5)

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

如果Collection只包含与你的Criteria相匹配的图片而你得到一个部分Collection会导致更新问题,因为Hibernate认为过滤后的项目已被删除并会更新数据库以反映这一变化,实际上从集合中删除项目。

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

答案 1 :(得分:1)

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

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); 
 }

答案 2 :(得分:0)

试试这个:

    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);   
    }     

答案 3 :(得分:0)

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

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

这个方法在一些hibernate版本中被删除了,如果是这样你也可以使用下面的解决方案: criteria with filtered complex set