6.1 Diep afhankelijkheidsbeheer
En nog wat meer nuttige en interessante dingen over @OneToMany- annotaties en dergelijke. Ze hebben allemaal 4 veelgebruikte opties:
- cascade = CascadeType.ALL
- weesVerwijdering = waar
- fetch = FetchType.LAZY
Nu zullen we ze in meer detail analyseren. En we beginnen met de meest interessante - CascadeType . Deze parameter bepaalt wat er moet gebeuren met afhankelijke entiteiten als we de hoofdentiteit wijzigen.
De JPA-specificatie heeft de volgende waarden voor deze parameter:
- ALLE
- VOLHARDEN
- SAMENVOEGEN
- VERWIJDEREN
- VERFRISSEN
- ONTKOPPELEN
Hibernate breidt deze specificatie echter uit met nog drie opties:
- REPLICEREN
- OPSLAAN_UPDATE
- SLOT
Er is natuurlijk een sterke parallel met de database en hun CONSTRANIS. Er zijn echter ook verschillen. Hibernate probeert het echte werk met de database zoveel mogelijk te verbergen, dus deze Hibernate Cascades gaan precies over Entity-objecten.
6.2 CascadeType
De cascadeparameter beschrijft wat er moet gebeuren met afhankelijke objecten als we hun ouder (hoofdobject) wijzigen. Meestal wordt deze parameter gebruikt in combinatie met annotaties die objectafhankelijkheden beschrijven:
Voorbeeld:
OneToOne(cascade = CascadeType.ALL)
Of zo:
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
Het kan ook als een afzonderlijke annotatie worden geschreven:
@Cascade({ org.hibernate.annotations.CascadeType.ALL })
Laten we het nu hebben over wat deze annotaties betekenen.
6.3 ALLES, VOLHOUDEN, SAMENVOEGEN
CascadeType.ALL
betekent dat alle acties die we uitvoeren met het bovenliggende object moeten worden herhaald voor de afhankelijke objecten.
CascadeType.PERSIST
betekent dat als we het bovenliggende object in de database opslaan, hetzelfde moet gebeuren met de afhankelijke objecten. Voorbeeld:
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.PERSIST, mappedBy="task")
private EmployeeTask task;
}
Een voorbeeld van werken met deze klasse:
Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
session.persist(director);
session.flush();
We slaan alleen een object van het type Employee op, het afhankelijke object EmployeeTask wordt automatisch in de database opgeslagen.
CascadeType.MERGE
betekent dat als we het bovenliggende object in de database bijwerken, hetzelfde moet gebeuren met de afhankelijke objecten.
6.4 VERWIJDEREN, WISSEN, ONTKOPPELEN
CascadeType.REMOVE
betekent dat als we een bovenliggend object in de database verwijderen, hetzelfde moet gebeuren met de afhankelijke objecten.
CascadeType.DELETE
betekent hetzelfde. Dit zijn synoniemen. Alleen uit andere specificaties.
CascadeType.DETACH
betekent dat als we het bovenliggende object uit de sessie verwijderen, hetzelfde moet gebeuren met de afhankelijke objecten. Voorbeeld:
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.DETACH, mappedBy="task")
private EmployeeTask task;
}
Een voorbeeld van werken met deze klasse:
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
en CascadeType.SAVE_UPDATE
werken op dezelfde manier als we verwachten - ze dupliceren de acties die worden uitgevoerd met het bovenliggende object naar het afhankelijke object.
6.5 Optie weeshuisverwijdering
Soms kom je ook de parameter tegen orphan
. Dit is een afkorting voor weesverwijdering. Het wordt gebruikt om ervoor te zorgen dat er geen onderliggende entiteiten zijn zonder bovenliggende entiteiten.
OneToOne(orphan = true)
Als deze parameter is ingesteld op true, wordt de onderliggende entiteit verwijderd als deze is verdwenenalle koppelingen. Het is niet precies hetzelfde als Cascade.REMOVE
.
U kunt een situatie hebben waarin meerdere bovenliggende entiteiten naar één kind verwijzen. Dan is het gunstig dat deze niet samen met het verwijderen van de bovenliggende entiteit wordt verwijderd, maar alleen als alle verwijzingen ernaar worden vernietigd.
Stel dat je een klas hebt:
@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();
Het object EmployeeTask wordt verwijderd omdat er geen verwijzingen meer naar zijn. Tegelijkertijd heeft niemand het bovenliggende object verwijderd.
6.6 ophaaloptie
Met de ophaaloptie kunt u bepalen hoe afhankelijke objecten worden geladen. Het duurt meestal een van de volgende twee waarden:
FetchType.LAZY
FetchType.EAGER
Dit is een heel interessant onderwerp met verschillende valkuilen, dus ik kan er maar beter over praten in een aparte lezing.