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.ALLoznacza, że ​​wszystkie akcje , które wykonujemy z obiektem nadrzędnym, muszą zostać powtórzone dla jego obiektów zależnych.

CascadeType.PERSISToznacza, ż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.MERGEoznacza, ż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.REMOVEoznacza, że ​​jeśli usuniemy obiekt nadrzędny w bazie danych, to samo trzeba zrobić z jego obiektami zależnymi.

CascadeType.DELETEoznacza to samo. To są synonimy. Po prostu z różnych specyfikacji.

CascadeType.DETACHoznacza, ż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.REFRESHi CascadeType.SAVE_UPDATEdział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.