/ / Hibernacja ManyToMany powoduje powstanie produktu kartezjańskiego - java, hibernacja, jpa

Hibernate ManyToMany daje efekt kartezjański - java, hibernate, jpa

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

wprowadź opis obrazu tutaj

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 № 1

Dzieje 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) dla tasks

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.