6.1 Gestione profonda delle dipendenze
E alcune cose più utili e interessanti sulle annotazioni @OneToMany e simili. Tutti hanno 4 opzioni comunemente usate:
- cascata = CascadeType.ALL
- orphanRemoval = vero
- fetch = FetchType.LAZY
Ora li analizzeremo in modo più dettagliato. E inizieremo con il più interessante - CascadeType . Questo parametro determina cosa dovrebbe accadere alle entità dipendenti se cambiamo l'entità principale.
La specifica JPA ha i seguenti valori per questo parametro:
- TUTTO
- PERSISTERE
- UNISCI
- RIMUOVERE
- RICARICARE
- STACCARE
Tuttavia, Hibernate espande questa specifica in altre tre opzioni:
- REPLICARE
- SALVA_AGGIORNA
- SERRATURA
C'è, ovviamente, un forte parallelo con il database e il loro CONSTRANIS. Tuttavia, ci sono anche differenze. Hibernate cerca di nascondere il più possibile il vero lavoro con il database, quindi questi Hibernate Cascades riguardano esattamente gli oggetti Entity.
6.2 Tipo Cascata
Il parametro cascade descrive cosa dovrebbe accadere agli oggetti dipendenti se cambiamo il loro genitore (oggetto principale). Molto spesso, questo parametro viene utilizzato insieme alle annotazioni che descrivono le dipendenze degli oggetti:
Esempio:
OneToOne(cascade = CascadeType.ALL)
O così:
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
Può anche essere scritto come annotazione separata:
@Cascade({ org.hibernate.annotations.CascadeType.ALL })
Ora parliamo di più sul significato di queste annotazioni.
6.3 TUTTO, PERSISTERE, UNIRE
CascadeType.ALL
significa che tutte le azioni che eseguiamo con l'oggetto genitore devono essere ripetute per i suoi oggetti dipendenti.
CascadeType.PERSIST
significa che se salviamo l'oggetto genitore nel database, lo stesso deve essere fatto con i suoi oggetti dipendenti. Esempio:
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.PERSIST, mappedBy="task")
private EmployeeTask task;
}
Un esempio di lavoro con questa classe:
Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
session.persist(director);
session.flush();
Salviamo solo un oggetto di tipo Employee, il suo oggetto dipendente EmployeeTask verrà salvato automaticamente nel database.
CascadeType.MERGE
significa che se aggiorniamo l'oggetto padre nel database, lo stesso deve essere fatto con i suoi oggetti dipendenti.
6.4 RIMUOVERE, CANCELLARE, STACCARE
CascadeType.REMOVE
significa che se eliminiamo un oggetto genitore nel database, lo stesso deve essere fatto con i suoi oggetti dipendenti.
CascadeType.DELETE
significa lo stesso. Questi sono sinonimi. Solo da specifiche diverse.
CascadeType.DETACH
significa che se rimuoviamo l'oggetto genitore dalla sessione, lo stesso deve essere fatto con i suoi oggetti dipendenti. Esempio:
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.DETACH, mappedBy="task")
private EmployeeTask task;
}
Un esempio di lavoro con questa classe:
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
e CascadeType.SAVE_UPDATE
funzionano nello stesso modo in cui ci aspettiamo: duplicano le azioni eseguite con l'oggetto genitore sul suo oggetto dipendente.
6.5 Opzione di rimozione degli orfani
Inoltre a volte potresti imbatterti nel parametro orphan
. Questo è l'abbreviazione di rimozione degli orfani. Viene utilizzato per garantire che non vi siano entità figlio senza entità padre.
OneToOne(orphan = true)
Se questo parametro è impostato su true, l'entità figlio verrà eliminata se è scomparsatutti i collegamenti. Non è esattamente lo stesso di Cascade.REMOVE
.
Potresti avere una situazione in cui diverse entità padre fanno riferimento a un figlio. Quindi è vantaggioso che non venga eliminato insieme alla cancellazione dell'entità madre, ma solo se tutti i riferimenti ad esso vengono annullati.
Diciamo che hai una classe:
@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();
L'oggetto EmployeeTask verrà eliminato perché non sono rimasti riferimenti ad esso. Allo stesso tempo, nessuno ha eliminato l'oggetto padre.
6.6 opzione di recupero
L'opzione fetch consente di controllare come vengono caricati gli oggetti dipendenti. Di solito assume uno dei due valori:
FetchType.LAZY
FetchType.EAGER
Questo è un argomento molto interessante con varie insidie, quindi è meglio che ne parli in una lezione separata.
GO TO FULL VERSION