Jestem nowicjuszem w hibernacji / JPA i przepraszam za to pytanie noob. Podążam za relacjami z bytami
- Menedżer ma wiele do wielu relacji z pracownikiem
- Pracownik ma wiele do wielu relacji z Zadaniem
Poniżej znajduje się ERD
Poniżej znajdują się moje klasy Java
@Entity
@table(name="manager")
public class Manager {
private long id;
private String name;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "manager_worker", joinColumns = { @JoinColumn(name = "manager_id") },
inverseJoinColumns = { @JoinColumn(name = "worker_id") })
private ArrayList<Worker> workers = new ArrayList<Worker>();
// ......getter setter
}
@Entity
@Table(name = "worker")
public class Worker {
@Id
private long id;
private String name;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "worker_task", joinColumns = { @JoinColumn(name = "worker_id") },
inverseJoinColumns = { @JoinColumn(name = "task_id") })
private ArrayList<Task> tasks = new ArrayList<Task>();
...........................
}
@Entity
@Table(name = "task")
public class Task {
@Id
private long id;
private String title;
.................
}
Mam następujące dane:
- Menedżer M1 ma pracowników W1 i W2
- W1 ma zadania TW1, TW2, TW3
- W2 ma zadania TW2 i TW2
Gdy otrzymam obiekt Menedżera dla Id M1, wynikma iloczyn kartezjański produktu Worker and Task, tj. dane W1 są powtarzane 3 razy, a dane W2 są powtarzane 2 razy, tj. lista tablic menedżera. pracownik ma 5 obiektów roboczych zamiast 2.
Aby załadować dane, używam metody Session.get ()
public E find(final K key) {
return (E) currentSession().get(daoType, key);
}
Czy ktoś może mi powiedzieć, jak to naprawić i wskazać najlepsze praktyki, które powinienem zastosować w tym przypadku.
Dzięki
Odpowiedzi:
3 dla odpowiedzi № 1Dzieje się tak, ponieważ jedno i drugie @ManyToMany
relacje są chętnie ładowane.
Spowoduje to zewnętrzne połączenie wszystkich trzech tabel. Wynikiem tego zapytania jest pięć wierszy, w których W1 pojawia się trzy razy, a W2 dwa razy. Jak dotąd wszystko jest w porządku.
Ale z jakiegoś powodu Hibernacja po prostu umieszcza wszystkich pracowników w kolekcjach, nawet jeśli są duplikatami. Jest nawet opisane w FAQ.
Istnieje wiele opcji rozwiązania tego problemu:
- zmień jedną z relacji na leniwe ładowanie
- użyj zestawu zamiast listy (nie powinieneś używać
ArrayList
jako typ zmiennych i tak, szczególnie przy użyciu Hibernacji) - posługiwać się
@Fetch(FetchMode.SELECT)
dlatasks
2 dla odpowiedzi nr 2
Gdzie jest twój targetEntity
w @ManyToMany
związek?
powinieneś mieć coś takiego:
@ManyToMany(targetEntity = Task.class)
@JoinTable(name = "worker_task", joinColumns = { @JoinColumn(name = "worker_id") },
inverseJoinColumns = { @JoinColumn(name = "task_id") })
private ArrayList<Task> tasks = new ArrayList<Task>();
Proponuję zmienić na @OneToMany
i @ManyToOne
związek tak czy inaczej. Ta koncepcja jest bardziej zgodna z projektem bazy danych i jest bardziej zrozumiała, gdy osoba patrzy na ERD. Więc Manager
ma relację jeden-do-wielu z Managerem-Workerem, dlatego manager_worker ma relację jeden-do-jednego z Managerem. Zachowaj to samo dla pozostałych bytów.