【问题标题】:Hibernate Criteria API - Filtering collection propertyHibernate Criteria API - 过滤集合属性
【发布时间】:2011-08-31 10:09:43
【问题描述】:

我有这样的实体:

@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 的图片数量,但在相册中我得到所有图片。

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

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

【问题讨论】:

  • 原谅我的语言不通;)
  • 你有没有尝试观察hibernate生成的sql查询?
  • 我已经写好了。有一个 SQL 查询只检索到 4 张图片,但后来我发现,还有另一个检索所有照片。我开始相信我的案例无法使用 Criteria API 实现:(
  • 我得出了一些结论。过滤与实体关联的集合是不安全的。交易退出期间会有更新。所以根据定义,一些图片将从相册中删除。这是错误的行为。所以...集合应该是只读的(不能插入也不能更新),否则由于安全原因,这种情况无法实现。不幸的是,目前我没有我的代码,无法检查它。

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


【解决方案1】:

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

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

此方法在某些休眠版本中已弃用,如果是这样,您也可以使用以下解决方案: criteria with filtered complex set

【讨论】:

    【解决方案2】:

    试试这个:

        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】:

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

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

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

      【讨论】:

      • 是的,您可以使用子标准,如下所述。但这有点令人费解,我更喜欢使用 HQL 和 JOIN。
      【解决方案4】:

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

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

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 2015-12-30
      相关资源
      最近更新 更多