6.1 Managementul profund al dependenței

Și câteva lucruri mai utile și interesante despre adnotările @OneToMany și altele asemenea. Toate au 4 opțiuni frecvent utilizate:

  • cascadă = CascadeType.ALL
  • orphanRemoval = adevărat
  • fetch = FetchType.LAZY

Acum le vom analiza mai detaliat. Și vom începe cu cel mai interesant - CascadeType . Acest parametru determină ce ar trebui să se întâmple cu entitățile dependente dacă schimbăm entitatea principală.

Specificația JPA are următoarele valori pentru acest parametru:

  • TOATE
  • PERSISTA
  • COMBINA
  • ELIMINA
  • REÎMPROSPĂTA
  • DESPRINDE

Cu toate acestea, Hibernate extinde această specificație în încă trei opțiuni:

  • REPLICAȚI
  • SAVE_UPDATE
  • LACĂT

Există, desigur, o paralelă puternică cu baza de date și CONSTRANI-urile lor. Cu toate acestea, există și diferențe. Hibernate încearcă să ascundă munca reală cu baza de date cât mai mult posibil, astfel încât aceste Cascade Hibernate sunt exact despre obiecte Entity.

6.2 CascadeType

Parametrul cascadă descrie ce ar trebui să se întâmple cu obiectele dependente dacă le schimbăm părintele (obiectul principal). Cel mai adesea, acest parametru este utilizat împreună cu adnotări care descriu dependențele obiectelor:

Exemplu:

OneToOne(cascade = CascadeType.ALL)

Sau cam asa:

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})

Poate fi scris și ca adnotare separată:

@Cascade({ org.hibernate.annotations.CascadeType.ALL })

Acum să vorbim mai multe despre ce înseamnă aceste adnotări.

6.3 TOATE, PERSISTĂ, FUNCȚI

CascadeType.ALLînseamnă că toate acțiunile pe care le realizăm cu obiectul părinte trebuie repetate pentru obiectele sale dependente.

CascadeType.PERSISTînseamnă că dacă salvăm obiectul părinte în baza de date, atunci același lucru trebuie făcut și cu obiectele sale dependente. Exemplu:


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToOne(cascade = CascadeType.PERSIST, mappedBy="task")
   private EmployeeTask task;
}

Un exemplu de lucru cu această clasă:


Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
 
session.persist(director);
session.flush();

Salvăm doar un obiect de tip Employee, obiectul dependent EmployeeTask va fi salvat automat în baza de date.

CascadeType.MERGEînseamnă că dacă actualizăm obiectul părinte din baza de date, atunci același lucru trebuie făcut și cu obiectele sale dependente.

6.4 ȘTERGERE, ȘTERGERE, DETASARE

CascadeType.REMOVEînseamnă că dacă ștergem un obiect părinte din baza de date, atunci același lucru trebuie făcut cu obiectele sale dependente.

CascadeType.DELETEinseamna acelasi lucru. Acestea sunt sinonime. Doar din specificații diferite.

CascadeType.DETACHînseamnă că dacă eliminăm obiectul părinte din sesiune, atunci același lucru trebuie făcut și cu obiectele sale dependente. Exemplu:


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToOne(cascade = CascadeType.DETACH, mappedBy="task")
   private EmployeeTask task;
}

Un exemplu de lucru cu această clasă:


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_UPDATEfuncționează în același mod în care ne așteptăm - dublează acțiunile care sunt efectuate cu obiectul părinte la obiectul său dependent.

6.5 Opțiune de eliminare orfană

De asemenea, uneori s-ar putea să dai peste parametrul orphan. Aceasta este prescurtarea pentru eliminarea orfanilor. Este folosit pentru a se asigura că nu există entități copil fără entități părinte.

OneToOne(orphan = true)

Dacă acest parametru este setat la adevărat, atunci entitatea copil va fi ștearsă dacă a dispăruttoate linkurile. Nu este exact la fel cu Cascade.REMOVE.

Este posibil să aveți o situație în care mai multe entități părinte se referă la un copil. Atunci este benefic ca acesta să nu fie șters odată cu ștergerea entității-mamă, ci numai dacă toate referirile la aceasta sunt anulate.

Să presupunem că aveți o clasă:


@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();

Obiectul EmployeeTask va fi șters deoarece nu au mai rămas referințe la el. În același timp, nimeni nu a șters obiectul părinte.

6.6 opțiune de preluare

Opțiunea de preluare vă permite să controlați modul în care sunt încărcate obiectele dependente. De obicei, ia una dintre cele două valori:

  • FetchType.LAZY
  • FetchType.EAGER

Acesta este un subiect foarte interesant, cu diverse capcane, așa că ar fi mai bine să vorbesc despre el într-o prelegere separată.