java-在Hibernate中,当有EAGER JOIN时,StatelessSession是否防止过滤出重复项

前端之家收集整理的这篇文章主要介绍了java-在Hibernate中,当有EAGER JOIN时,StatelessSession是否防止过滤出重复项 前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

我有一个Song类,其中包含CoverArts的集合

例如

  1. @OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.ALL})
  2. @JoinColumn(name = "recNo")
  3. private List<CoverArt> coverArts;

并且正在使用Hibernate 4.3.11和DB2数据库,并且我有这个查询,用于按其主键及其CoverArt检索歌曲列表.

  1. public static List<Song> getSongsWithCoverArtFromDatabase(Session session,List<Integer> ids)
  2. {
  3. try
  4. {
  5. Criteria c = session
  6. .createCriteria(Song.class)
  7. .setFetchMode("coverArts",FetchMode.JOIN)
  8. .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
  9. .add(Restrictions.in("recNo",ids));
  10. List<Song> songs = c.list();
  11. return songs;
  12. }
  13. catch (Exception e)
  14. {
  15. MainWindow.logger.log(Level.SEVERE,"Failed LoadSongToDatabase:" + e.getMessage(),e);
  16. throw new RuntimeException(e);
  17. }
  18. }

请注意,我们已经在coverArts集合上将获取模式设置为JOIN,并且需要设置setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY),否则,如果我们有一首带有两个Coverart记录的歌曲,我们将返回两个Song对象.但是,当使用Criteria.DISTINCT_ROOT_ENTITY时,Hibernate将正确返回一首包含两个CoverArt的乐曲.

但是我只是尝试使用StatelessSession做同样的事情.原因是我只是试图选择用于创建报告的数据,但是我想最大化速度并最小化内存消耗,但是

  1. public static List<Song> getSongsWithCoverArtFromDatabase(StatelessSession session,e);
  2. throw new RuntimeException(e);
  3. }
  4. }

这似乎忽略了.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)并返回重复行.

这是一个已知的错误,它意味着什么?

最佳答案
看起来这在Hibernate中实现StatelessSessionImpl的方式是有缺陷的,但是也可能正在解决此问题.

显然,使用FetchMode.JOIN,SQL查询将在两个表之间(左外侧)联接,因此每首歌曲可能返回几行.通常,Hibernate解析通过其PersistenceContext返回的每一行.

如果感兴趣的话,您可以在Loader here的Hibernate源代码中看到它.然后,根据Session的类型,SessionImpl.getEntityUsingInterceptor()与PersistenceContext进行通信,但是StatelessSessionImpl.getEntityUsingInterceptor()只是返回null.但是,此方法有一个later commit看起来可以做正确的事.提交是HHH-11147的一部分,其中说修订版本是Hibernate 5.3.11和5.4.4-在撰写本文时未显示Maven repo中.

同时,一种解决方法是投放自己的ResultTransformer.这是一个相当“关键”的例子:

  1. public class DistinctSongResultTransformer implements ResultTransformer {
  2. private ResultTransformer defaultTransformer = Criteria.DISTINCT_ROOT_ENTITY;
  3. @Override
  4. public Object transformTuple(Object[] tuple,String[] aliases) {
  5. return defaultTransformer.transformTuple(tuple,aliases);
  6. }
  7. @SuppressWarnings("rawtypes")
  8. @Override
  9. public List transformList(List collection) {
  10. Map<Integer,Song> distinctSongs = new LinkedHashMap<>();
  11. for (Object object : collection) {
  12. Song song = (Song) object;
  13. distinctSongs.putIfAbsent(song.getId(),song);
  14. }
  15. return new ArrayList<>(distinctSongs.values());
  16. }
  17. }

不同之处在于正常的DistinctRootEntityResultTransformer假定会话中将只有该实体的唯一实例-您可以看到比较here.

显然,还有空间使该示例也更具可重用性,尤其是抽象getId()的空间.

猜你在找的Java相关文章