6.1 Głębokie zarządzanie zależnościami
I kilka bardziej przydatnych i interesujących rzeczy na temat adnotacji @OneToMany i tym podobnych. Wszystkie mają 4 często używane opcje:
- kaskada = typkaskady.ALL
- usuniecie sieroty = prawda
- fetch = FetchType.LAZY
Teraz przeanalizujemy je bardziej szczegółowo. A zaczniemy od najciekawszego - CascadeType . Ten parametr określa, co powinno się stać z encjami zależnymi, jeśli zmienimy encję główną.
Specyfikacja JPA ma następujące wartości dla tego parametru:
- WSZYSTKO
- TRWAĆ
- ŁĄCZYĆ
- USUNĄĆ
- ODŚWIEŻAĆ
- ODŁĄCZYĆ
Jednak Hibernate rozszerza tę specyfikację o trzy dodatkowe opcje:
- REPLIKA
- SAVE_UPDATE
- ZAMEK
Istnieje oczywiście silna paralela z bazą danych i ich CONSTRANIS. Istnieją jednak również różnice. Hibernate stara się jak najbardziej ukryć rzeczywistą pracę z bazą danych, więc te kaskady Hibernate dotyczą dokładnie obiektów Entity.
6.2 Typ kaskadowy
Parametr kaskady opisuje, co powinno się stać z obiektami zależnymi, jeśli zmienimy ich rodzica (obiekt główny). Najczęściej ten parametr jest używany razem z adnotacjami opisującymi zależności obiektów:
Przykład:
OneToOne(cascade = CascadeType.ALL)
Lub tak:
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
Można to również zapisać jako osobną adnotację:
@Cascade({ org.hibernate.annotations.CascadeType.ALL })
Porozmawiajmy teraz o tym, co oznaczają te adnotacje.
6.3 WSZYSTKO, UTRZYMUJ SIĘ, POŁĄCZ
CascadeType.ALL
oznacza, że wszystkie akcje , które wykonujemy z obiektem nadrzędnym, muszą zostać powtórzone dla jego obiektów zależnych.
CascadeType.PERSIST
oznacza, że jeśli zapiszemy obiekt nadrzędny do bazy danych, to samo trzeba zrobić z jego obiektami zależnymi. Przykład:
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.PERSIST, mappedBy="task")
private EmployeeTask task;
}
Przykład pracy z tą klasą:
Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
session.persist(director);
session.flush();
Zapisujemy tylko obiekt typu Pracownik, jego obiekt zależny PracownikZadanie zostanie automatycznie zapisany do bazy danych.
CascadeType.MERGE
oznacza, że jeśli aktualizujemy obiekt nadrzędny w bazie danych, to samo trzeba zrobić z jego obiektami zależnymi.
6.4 USUŃ, USUŃ, ODŁĄCZ
CascadeType.REMOVE
oznacza, że jeśli usuniemy obiekt nadrzędny w bazie danych, to samo trzeba zrobić z jego obiektami zależnymi.
CascadeType.DELETE
oznacza to samo. To są synonimy. Po prostu z różnych specyfikacji.
CascadeType.DETACH
oznacza, że jeśli usuniemy obiekt nadrzędny z sesji, to samo trzeba zrobić z jego obiektami zależnymi. Przykład:
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.DETACH, mappedBy="task")
private EmployeeTask task;
}
Przykład pracy z tą klasą:
Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
director.task = task;
session.flush();
assertThat(session.contains(director)).isTrue();
assertThat(session.contains(task)).isTrue();
session.detach(director);
assertThat(session.contains(director)).isFalse();
assertThat(session.contains(task)).isFalse();
CascadeType.REFRESH
i CascadeType.SAVE_UPDATE
działają w taki sam sposób, jak tego oczekujemy - powielają działania, które są wykonywane z obiektem nadrzędnym, na jego obiekt zależny.
6.5 Opcja usuwania sierot
Czasami możesz też natknąć się na parametr orphan
. Jest to skrót od usuwania sierot. Służy do upewnienia się, że nie ma jednostek podrzędnych bez jednostek nadrzędnych.
OneToOne(orphan = true)
Jeśli ten parametr jest ustawiony na wartość true, jednostka podrzędna zostanie usunięta, jeśli zniknęławszystkie linki. To nie jest dokładnie to samo co Cascade.REMOVE
.
Możesz mieć sytuację, w której kilka jednostek nadrzędnych odwołuje się do jednego dziecka. Wtedy korzystne jest, aby nie był usuwany wraz z usuwaniem podmiotu nadrzędnego, ale tylko wtedy, gdy wszystkie odwołania do niego zostaną unieważnione.
Powiedzmy, że masz klasę:
@Entity
@Table(name="user")
class Employee {
@Column(name="id")
public Integer id;
@OneToMany(cascade = CascadeType.ALL, orphan = true)
@JoinColumn(name = "employee_id")
private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();
}
Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.tasks.get(0);
director.tasks.remove(task)
session.persist(director);
session.flush();
Obiekt EmployeeTask zostanie usunięty, ponieważ nie ma do niego żadnych odwołań. W tym samym czasie nikt nie usunął obiektu nadrzędnego.
6.6 opcja pobierania
Opcja pobierania pozwala kontrolować sposób ładowania zależnych obiektów. Zwykle przyjmuje jedną z dwóch wartości:
FetchType.LAZY
FetchType.EAGER
To bardzo ciekawy temat z różnymi pułapkami, więc lepiej opowiem o tym w osobnym wykładzie.