Hibernate Criteria API - 过滤集合属性

发布于 2024-11-08 21:26:21 字数 1594 浏览 0 评论 0原文

我有这样的实体:

@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 我想获得带有过滤后的图片集的唯一 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),而不是不同的结果。

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

I have such entity:

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

and another one:

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

Using Criteria API I want to get unique AlbumDs with filtered set of Picturs. I try something like this:

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

And here I get Album with all pictures associated. They're not filtered at all.
When I try to execute query printed by a logger, I get only four rows wich is the number of pictures with given eventId, but in the Album I get all pictures.

I also tried other ResultTransformers, but eventualy got many result (4) not distinct one.

What do I miss or do wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我很OK 2024-11-15 21:26:21

您无法通过在查询中包含对集合的限制来过滤与实体关联的集合的内容。该查询只会获取相册。当集合被访问时,可以稍后获取集合的内容。您要做的就是过滤相册以仅检索包含具有事件 ID 的图片的相册。

如果集合仅包含与您的条件匹配的图片,并且您将获得部分集合,则会导致更新问题,因为 Hibernate 会认为过滤的项目已被删除,并会更新数据库以反映该更改,实际上会删除这些项目来自收藏。

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

You can not filter the content of Collections associated with an entity by including Restrictions on the Collection in the query. The query will only fetch the Albums. The content of the Collection can be fetched later, when the Collection is accessed. All you do is filter the Albums to retrieve only those Albums that contain the Pictures with the event ids.

If the Collection would only contain the Pictures that match your Criteria and you would get a partial Collection it would cause problems on updates, because Hibernate then think the filtered items have been removed and would update the database to reflect that change, actually removing the items from the Collection.

If you want to receive only some items from a Collection you can use the Session.createFilter() method. The only problem is, that it only supports HQL queries currently.

甜宝宝 2024-11-15 21:26:21

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

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

I recall this being an issue for something I did recently. Have you tried this:

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); 
 }
枕花眠 2024-11-15 21:26:21

试试这个:

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

try this:

    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);   
    }     
风筝在阴天搁浅。 2024-11-15 21:26:21

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

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

此方法在某些 hibernate 版本中已被弃用,如果是这样,您也可以使用以下解决方案:
具有过滤复杂集的条件

If you use alias with left_join, it will return just sub object which satisfy related condition. Otherwise it returns main object which satisfy conditions but with all of sub object set.

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

This method is deprrecated in some hibernate version, if so you can use below solution for it too:
criteria with filtered complex set

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文