CollectionOfElementsとしてマップされた値のコレクションを持つSynonymMappingというクラスがあります
@Entity(name = "synonymmapping")
public class SynonymMapping {
@Id private String keyId;
//@CollectionOfElements(fetch = FetchType.EAGER)
@CollectionOfElements
@JoinTable(name="synonymmappingvalues", joinColumns={@JoinColumn(name="keyId")})
@Column(name="value", nullable=false)
@Sort(type=SortType.NATURAL)
private SortedSet<String> values;
public SynonymMapping() {
values = new TreeSet<String>();
}
public SynonymMapping(String key, SortedSet<String> values) {
this();
this.keyId = key;
this.values = values;
}
public String getKeyId() {
return keyId;
}
public Set<String> getValues() {
return values;
}
}
2つのSynonymMappingオブジェクトをデータベースに保存し、保存したすべてのSynonymMappingオブジェクトを返すようにデータベースに要求し、保存した2つのオブジェクトを受信することを期待するテストがあります。
値のマッピングを変更して(コードのコメント化された行でコードに示されているように)熱心にテストを再実行すると、4つの一致が表示されます。
実行と実行の間にデータベースをクリアしました。この問題は、熱心なものと怠惰なものとの間で交換できます。
Hibernateがその下に作成する結合に関係していると思いますが、オンラインで明確な答えを見つけることができません。
熱心なフェッチがオブジェクトを複製している理由を誰かに教えてもらえますか?
ありがとう。
一般に、マッピングで熱心なフェッチを強制することはお勧めしません-適切なクエリで熱心な結合を指定することをお勧めします(すべての状況でオブジェクトが意味をなさない/そのコレクションなしで有効であることを100%確信している場合を除く)投入されます)。
重複が発生する理由は、Hibernateがルートテーブルとコレクションテーブルを内部的に結合するためです。それらは実際には重複していることに注意してください。それぞれが3つのコレクション要素を持つ2つのSynonymMappingsの場合、6つの結果(2x3)、各SynonymMappingエンティティの3つのコピーが得られます。したがって、最も簡単な回避策は、結果をセットにラップして、結果が一意であることを確認することです。
私は同じ問題に踏み込みました。@ CollectionOfElementsにFetchType.EAGERを設定すると、Hibernateはすべてを一度に取得しようとします。つまり、「マスター」オブジェクトにリンクされた要素のエントリごとに1つのクエリを使用します。コレクションに@Fetch(FetchMode.SELECT)アノテーションを追加すると、この問題はN + 1クエリのコストで正常に解決できます。私の場合、メタデータアイテム(ビデオコーデック、オーディオコーデック、サイズなど)のコレクションを持つMediaObjectエンティティが必要でした。 metadataItemsコレクションのマッピングは次のようになります。
@ CollectionOfElements(targetElement = String.class、fetch = FetchType.EAGER) @ JoinTable(name = "mo_metadata_item"、joinColumns = @JoinColumn(name = "media_object_id") ) @ MapKey(columns = @Column(name = "name")) @ Column(name = "value") @ Fetch(FetchMode.SELECT) private Map <String、String> metadataItems = new HashMap <String、String>();
私はこの問題に直面し、私はそれを使って解決しました
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
これにより、子テーブルに対して行われた結合によって発生する重複が解消されます。
SELECT DISTINCT(Hibernate Query Language)句を次のように使用できます
SELECT DISTINCT synonym FROM SynonymMapping synonym LEFT JOIN FETCH synonym.values
DISTINCT句は、Hibernateの重複した参照を削除します。
コンポーネントと値タイプのコレクションはどちらも、そのライフサイクルが所有エンティティクラスにバインドされていますが、それらを取得するには、select句で宣言する必要があります。 (LEFT JOIN FETCH synonym.values)
ChssPly76の答えは別のアプローチですが、Setのセマンティックに従ってオーバーライドの等しいとハッシュコードメソッドを忘れないでください
よろしく、
N + 1クエリで_FetchMode.SELECT
_を使用する代わりに、BatchSize
e.q. @BatchSize(size = 200)
。
DISTINCT
および_Criteria.DISTINCT_ROOT_ENTITY
_は、複数の関連付けを取得する必要がある場合には役に立ちません。この場合は、他のソリューションを参照してください: https://stackoverflow.com/a/46013654/54847
私は単に追加することでそれを達成しました
session.createCriteria(ModelClass.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
これは重複を取り除くのに役立ちます。