Дублирование значений при использовании @ElementCollection и @OneToMany.md
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
8c8719fcd1
commit
27b029e134
@ -0,0 +1,48 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-09-06
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 Hibernate|00 Hibernate]]"
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Столкнулся с неочевидным поведением `@ElementCollection` в связке с `@OneToMany`. Может случиться так, что в `@OneToMany` будет дублирование значений из-за `@ElementCollection`. Проще объяснить на примере.
|
||||
|
||||
Допустим у нас есть три таблицы: `user`, `user_nickname`, `address`. Есть сущность `User`:
|
||||
|
||||
```java
|
||||
@Entity
|
||||
public class User {
|
||||
|
||||
// ... ... ... ... ...
|
||||
|
||||
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
|
||||
private List<Address> stages = new ArrayList<>();
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name = "user_nickname",
|
||||
joinColumns = @JoinColumn(name = "user_id")
|
||||
)
|
||||
@Column(name = "nickname")
|
||||
private Set<String> nicknames = new HashSet<>();
|
||||
|
||||
// ... ... ... ... ...
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Допустим у нас одна запись про пользователя, у которого есть три адреса и один никнейм. В этом случае все хорошо, все придет корректно.
|
||||
|
||||
==Добавим этому пользователю еще один никнейм. Теперь мы получаем шесть адресов и два никнейма. Откуда взялись еще три лишних адреса, в базе данных их все еще три.== Это дубликаты. При этом, если вы воспользуетесь пагинацией JPA, то дублей уже не будет. It is magic 💫
|
||||
|
||||
Магии в программировании, как вы понимаете, нет. Они создаются при использовании `FetchType.EAGER` у `@OneToMany` в совокупности с `@ElementCollection(fetch = FetchType.EAGER)`. Hibernate генерирует запрос с двумя-тремя полными соединениями, отсюда и берутся дубли. При этом в пагинации Hibernate не генерирует джойны, а использует кучу селектов, отсюда и отсутствие дублей при пагинации.
|
||||
|
||||
Эта проблема решается несколькими способами:
|
||||
|
||||
- Переделайте `List` в `Set` у `@OneToMany`.
|
||||
- Уберите `FetchType.EAGER` у `@OneToMany`.
|
||||
- Добавьте `@Fetch(FetchMode.SUBSELECT)` у `@OneToMany`. это аннотация Hibernate, которая вместо JOIN использует подзапрос. О [подзапросах я писал в отдельной статье](https://struchkov.dev/blog/ru/select-subquery).
|
@ -5,5 +5,5 @@ tags:
|
||||
- type/zero-link
|
||||
title: Hibernate
|
||||
---
|
||||
- [Дублирование значений при использовании @ElementCollection и @OneToMany](../../../../_inbox/Дублирование%20значений%20при%20использовании%20@ElementCollection%20и%20@OneToMany.md)
|
||||
- [Дублирование значений при использовании @ElementCollection и @OneToMany](../../dev/java/hibernate/Дублирование%20значений%20при%20использовании%20@ElementCollection%20и%20@OneToMany.md)
|
||||
- [Логирование SQL в Hibernate](../../dev/java/hibernate/Логирование%20SQL%20в%20Hibernate.md)
|
Loading…
Reference in New Issue
Block a user