gpt4 book ai didi

java - 在 Hibernate 中,StatelessSession 在有 EAGER JOIN 时防止过滤掉重复项

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:05:40 27 4
gpt4 key购买 nike

我有一个 Song 类,其中包含一组 CoverArt

例如

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

我正在使用 Hibernate 4.3.11 和 DB2 数据库,我有这个查询来通过主键和封面艺术检索歌曲列表。

public static List<Song> getSongsWithCoverArtFromDatabase(Session session, List<Integer> ids)
{
try
{
Criteria c = session
.createCriteria(Song.class)
.setFetchMode("coverArts", FetchMode.JOIN)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.add(Restrictions.in("recNo", ids));
List<Song> songs = c.list();
return songs;
}
catch (Exception e)
{
MainWindow.logger.log(Level.SEVERE, "Failed LoadSongToDatabase:" + e.getMessage(), e);
throw new RuntimeException(e);
}
}

请注意,我们已将 coverArts 集合的获取模式设置为 JOIN,并且我们需要设置 setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) ,否则如果我们有一首包含两个翻唱唱片的歌曲,我们将返回两个 Song 对象。但是当使用 Criteria.DISTINCT_ROOT_ENTITY 时,Hibernate 会正确地返回一首包含两个封面艺术的歌曲。

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

   public static List<Song> getSongsWithCoverArtFromDatabase(StatelessSession session, List<Integer> ids)
{
try
{
Criteria c = session
.createCriteria(Song.class)
.setFetchMode("coverArts", FetchMode.JOIN)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.add(Restrictions.in("recNo", ids));
List<Song> songs = c.list();
return songs;
}
catch (Exception e)
{
MainWindow.logger.log(Level.SEVERE, "Failed LoadSongToDatabase:" + e.getMessage(), e);
throw new RuntimeException(e);
}
}

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

这是一个已知的错误吗?它的行为方式是什么?

最佳答案

看起来这是 StatelessSessionImpl 在 Hibernate 中实现的方式的缺点,但修复可能也在路上......

很明显,对于 FetchMode.JOIN,SQL 查询将(左外)连接两个表,因此每首歌曲可能返回多行。通常,Hibernate 解析通过其 PersistenceContext 返回的每一行。

如果有兴趣,您可以在 Loader 的 Hibernate 源代码中看到这个 here .然后,根据 Session 的类型,SessionImpl.getEntityUsingInterceptor()PersistenceContext 对话,但是 StatelessSessionImpl.getEntityUsingInterceptor()只返回空值。但是有一个 later commit这种看起来做正确事情的方法。提交是 HHH-11147 的一部分,它表示修复版本是 Hibernate 5.3.11 和 5.4.4 - 未显示在 Maven repo 中在撰写本文时。

与此同时,一种解决方法是推出您自己的 ResultTransformer。这是一个相当“切题”的例子:

public class DistinctSongResultTransformer implements ResultTransformer {
private ResultTransformer defaultTransformer = Criteria.DISTINCT_ROOT_ENTITY;

@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return defaultTransformer.transformTuple(tuple, aliases);
}

@SuppressWarnings("rawtypes")
@Override
public List transformList(List collection) {
Map<Integer, Song> distinctSongs = new LinkedHashMap<>();
for (Object object : collection) {
Song song = (Song) object;
distinctSongs.putIfAbsent(song.getId(), song);
}
return new ArrayList<>(distinctSongs.values());
}
}

区别在于普通的 DistinctRootEntityResultTransformer 假定 session 中只有一个唯一的实体实例 - 你可以看到比较 here .

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

关于java - 在 Hibernate 中,StatelessSession 在有 EAGER JOIN 时防止过滤掉重复项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56528721/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com