Яке значення CascadeType.ALL для асоціації JPA @ManyToOne


210

Я думаю, що я неправильно зрозумів значення каскадування в контексті @ManyToOneвідносин.

Справа:

public class User {

   @OneToMany(fetch = FetchType.EAGER)
   protected Set<Address> userAddresses;

}

public class Address {

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
   protected User addressOwner;

}

У чому сенс cascade = CascadeType.ALL? Наприклад, якщо я видаляю певну адресу з бази даних, як те, що я додав, cascade = CascadeType.ALLвпливає на мої дані ( напевне User, я)?

Відповіді:


360

Сенс CascadeType.ALLполягає в тому, що наполегливість поширюватиме (каскадувати) всі EntityManagerоперації ( PERSIST, REMOVE, REFRESH, MERGE, DETACH) для відповідних суб'єктів.

У вашому випадку це здається поганою ідеєю, оскільки видалення Addressзнака призведе до видалення пов'язаного User. Оскільки користувач може мати декілька адрес, інші адреси стануть сиротами. Однак зворотний випадок (анотування User) мав би сенс - якщо адреса належить лише одному користувачеві, можна безпечно розповсюдити видалення всіх адрес, що належать користувачеві, якщо цей користувач буде видалений.

BTW: ви можете додати mappedBy="addressOwner"атрибут до свого, Userщоб сигналізувати постачальнику завзятості про те, що стовпець приєднання повинен бути в таблиці АДРЕСА.


55
+1 для найкращого і найкоротшого пояснення на карті. Я коли-небудь стикався.
Ridcully

4
Було б добре мати CascadeType.ALL на стороні @OneToMany.
mvmn

48

Дивіться тут приклад із документів OpenJPA. CascadeType.ALLзначить, він буде робити всі дії.

Цитата:

CascadeType.PERSIST: Утримуючи суб'єкт господарювання, також зберігайте сутність, що міститься в його полях. Ми пропонуємо ліберальне застосування цього правила каскаду, тому що якщо EntityManager під час флеш знайде поле, яке посилається на нову сутність, а поле не використовує CascadeType.PERSIST, це помилка.

CascadeType.REMOVE: Видаляючи сутність, вона також видаляє об'єкти, що знаходяться в цьому полі.

CascadeType.REFRESH: Оновлюючи об'єкт, також оновіть об'єкти, що знаходяться в цьому полі.

CascadeType.MERGE: Під час об'єднання стану сутності також об'єднайте об'єкти, що знаходяться в цьому полі.

Себастьян


4
Нове в JPA, ця інформація є корисною, але що тут з деталізацією?
Сарц

1
У програмі CascadeType.DETACH під час відокремлення об'єкта вони також від'єднують об'єкти, якими володіє материнська структура.
Доріан Меєр

29

Як я пояснив у цій статті та у своїй книзі " Високопродуктивна підтримка Java , вам не слід користуватися CascadeType.ALLз @ManyToOneмоменту переходів стану сутності повинна поширюватися від батьківських організацій до дитини ті, а не навпаки.

The @ManyToOneСторона завжди Немовля асоціація , оскільки вона відображає основний стовпець зовнішнього ключа.

Тому вам слід перенести CascadeType.ALLз @ManyToOneасоціації в @OneToManyбік, який також повинен використовувати mappedByатрибут, оскільки це найефективніше відображення співвідношень таблиць між багатьма .


18

З специфікації EJB3.0 :

Використання елемента каскадної анотації може використовуватися для поширення ефекту операції на пов'язані об'єкти. Функціонал каскаду найчастіше використовується у відносинах батько-дитина.

Якщо X є керованою сутністю, операція видалення призводить до її видалення. Операція видалення каскадується до сутностей, на які посилається X, якщо зв'язки від X до цих інших об'єктів зазначаються каскадом = REMOVE або cascade = ВСЕ значення елемента анотації.

Отже, у двох словах, відносини сутності, визначені з CascadeType.All, забезпечать, щоб усі постійні події, такі як збереження, оновлення, злиття та видалення, що відбуваються у батьків, передавалися дитині. Визначення інших CascadeTypeваріантів забезпечує розробника більш детальним рівнем контролю над тим, як асоціація суб'єкта господарювання обробляє стійкість.

Наприклад, якщо у мене була книга "Об'єкт", яка містила "Список сторінок", і я додаю об'єкт сторінки в цей список. Якщо @OneToManyанотація, що визначає зв'язок між Книгою та Сторінкою, позначена як CascadeType.All, збереження Книги призведе до того, що Сторінка також зберігатиметься в базі даних.


11

У JPA 2.0, якщо ви хочете видалити адресу, якщо ви її видалили з об'єкта Користувача, ви можете додати її orphanRemoval=true(замість CascadeType.REMOVE) до своєї@OneToMany .

Більше пояснення між orphanRemoval=trueі CascadeType.REMOVEзнаходиться тут .


4

Якщо ви просто хочете видалити адресу, призначену користувачеві, і не впливати на клас сутності користувача, спробуйте щось подібне:

@Entity
public class User {
   @OneToMany(mappedBy = "addressOwner", cascade = CascadeType.ALL)
   protected Set<Address> userAddresses = new HashSet<>();
}

@Entity 
public class Addresses {
   @ManyToOne(cascade = CascadeType.REFRESH) @JoinColumn(name = "user_id")
   protected User addressOwner;
}

Таким чином, вам не потрібно турбуватися про використання завантаження в анотаціях. Але пам’ятайте, що при видаленні Користувача ви також видалите підключену адресу до об’єкта користувача.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.