私はCoverArtsのコレクションが含まれているソングのクラスを持っています
例えば
@OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
@JoinColumn(name = "recNo")
private List<CoverArt> coverArts;
そして、あなたは、Hibernate 4.3.11およびDB2データベースを使用している、と私は彼らのキーとそのCoverArt検索に応じて曲のリストにこのクエリを持っています。
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で組み立てられていることに注意してくださいは、参加するには設定され、あなたがセットsetResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)に必要な、我々は2 Coverartで録音した曲を持っている場合はそうでない場合は、我々は2ソングオブジェクトを返しますされてください。ただし、 Criteria.DISTINCT_ROOT_ENTITYを使用した場合、Hibernateは歌が正しく2つのCoverArtが含まれて返されます。
しかし、私はちょうどその理由は、私はちょうどレポートを作成するために使用されるデータを選択しようとしたことである。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が欠陥があるように思われたが、この問題を解決することも可能です。
明らかに、各楽曲は、2つのテーブル間の行を返すことができるように、FetchMode.JOIN、SQLクエリ(左外)接続を使用して典型的には、HibernateはそののPersistenceContextによって返された各行を解析します。
興味を持っている場合は、ローダーできる壁紙ここでは、セッションのタイプに応じて、その後。Hibernateのソースコードを見てSessionImpl.getEntityUsingInterceptor()のPersistenceContextと通信するために、しかしStatelessSessionImpl.getEntityUsingInterceptor()は単にヌルを返します。しかし、この方法をあり、後にコミットが正しいことをやっているようだ。提出はありHHH-11147リビジョンは、この書き込みには表示されません。Hibernateは5.3.11と5.4.4-であると言うその一部Mavenのレポインチ
同時に、1つの解決策は、彼らの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が唯一のエンティティのセッションでのみインスタンスということを前提としていることであるここの壁紙を。
明らかに、この例では、より再利用可能で、特に抽象のgetId()のスペースを作るための余地があります。