6.1 Управление на дълбоки зависимости
И още някои полезни и интересни неща за @OneToMany анотации и други подобни. Всички те имат 4 често използвани опции:
- cascade = CascadeType.ALL
- orphanRemoval = вярно
- fetch = FetchType.LAZY
Сега ще ги анализираме по-подробно. И ще започнем с най-интересното - CascadeType . Този параметър определя Howво трябва да се случи със зависимите обекти, ако променим основния обект.
Спецификацията на JPA има следните стойности за този параметър:
- ВСИЧКО
- УПОРСТВАМ
- СЛИВАНЕ
- ПРЕМАХВАНЕ
- ОБНОВЯВАНЕ
- ОТКАЧВАНЕ
Hibernate обаче разширява тази спецификация в още три опции:
- РЕПЛИКАЦИЯ
- SAVE_UPDATE
- КЛЮЧАЛКА
Разбира се, има силен паралел с базата данни и техния CONSTRANIS. Има обаче и разлики. Hibernate се опитва да скрие реалната работа с базата данни, доколкото е възможно, така че тези Hibernate Cascades са точно за обекти Entity.
6.2 CascadeType
Параметърът cascade описва Howво трябва да се случи със зависимите обекти, ако променим техния родител (главен обект). Най-често този параметър се използва заедно с анотации, които описват зависимостите на обекта:
Пример:
OneToOne(cascade = CascadeType.ALL)
Или така:
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
Може да се напише и като отделна анотация:
@Cascade({ org.hibernate.annotations.CascadeType.ALL })
Сега нека поговорим повече за това Howво означават тези анотации.
6.3 ALL, PERSIST, MERGE
CascadeType.ALL
означава, че всички действия , които извършваме с родителския обект, трябва да се повторят за неговите зависими обекти.
CascadeType.PERSIST
означава, че ако запазим родителския обект в базата данни, тогава същото трябва да се направи и с неговите зависими обекти. Пример:
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.PERSIST, mappedBy="task")
private EmployeeTask task;
}
Пример за работа с този клас:
Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
session.persist(director);
session.flush();
Ние запазваме само обект от тип Employee, неговият зависим обект EmployeeTask ще бъде записан в базата данни автоматично.
CascadeType.MERGE
означава, че ако актуализираме родителския обект в базата данни, тогава същото трябва да се направи и с неговите зависими обекти.
6.4 ПРЕМАХВАНЕ, ИЗТРИВАНЕ, ОТКАЧВАНЕ
CascadeType.REMOVE
означава, че ако изтрием родителски обект в базата данни, тогава същото трябва да се направи с неговите зависими обекти.
CascadeType.DELETE
означава същото. Това са синоними. Просто от различни спецификации.
CascadeType.DETACH
означава, че ако премахнем родителския обект от сесията, тогава същото трябва да се направи и с неговите зависими обекти. Пример:
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.DETACH, mappedBy="task")
private EmployeeTask task;
}
Пример за работа с този клас:
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
и CascadeType.SAVE_UPDATE
работят по същия начин, Howто очакваме - те дублират действията, които се извършват с родителския обект към неговия зависим обект.
6.5 Опция за премахване на осиротели
Също така понякога може да срещнете параметъра orphan
. Това е съкращение от Орфан премахване. Използва се, за да се гарантира, че няма дъщерни обекти без родителски обекти.
OneToOne(orphan = true)
Ако този параметър е зададен на true, тогава дъщерният обект ще бъде изтрит, ако е изчезналвсички връзки. Не е точно същото като Cascade.REMOVE
.
Може да имате ситуация, при която няколко родителски обекта се отнасят за едно дете. Тогава е полезно той да не се изтрива заедно с изтриването на родителския обект, а само ако всички препратки към него са анулирани.
Да приемем, че имате клас:
@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();
Обектът EmployeeTask ще бъде изтрит, защото няма останали препратки към него. В същото време никой не е изтрил родителския обект.
6.6 опция за извличане
Опцията за извличане ви позволява да контролирате How се зареждат зависимите обекти. Обикновено приема една от двете стойности:
FetchType.LAZY
FetchType.EAGER
Това е много интересна тема с различни подводни камъни, така че е по-добре да говоря за нея в отделна лекция.
GO TO FULL VERSION