Что означает CascadeType.ALL для ассоциации @ManyToOne JPA

Я думаю, что неправильно понял значение каскадирования в контексте @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)?


person forhas    schedule 23.10.2012    source источник


Ответы (6)


Значение CascadeType.ALL состоит в том, что постоянство будет распространять (каскадно) все EntityManager операции (PERSIST, REMOVE, REFRESH, MERGE, DETACH) на связанные сущности.

В вашем случае это плохая идея, так как удаление Address приведет к удалению соответствующего User. Поскольку у пользователя может быть несколько адресов, другие адреса останутся безвозвратными. Однако обратный случай (аннотирование User) имеет смысл - если адрес принадлежит только одному пользователю, можно безопасно распространить удаление всех адресов, принадлежащих пользователю, если этот пользователь будет удален.

Кстати: вы можете добавить атрибут mappedBy="addressOwner" в свой User, чтобы сообщить поставщику постоянства, что столбец соединения должен быть в таблице ADDRESS.

person kostja    schedule 23.10.2012
comment
Хотя было бы неплохо иметь CascadeType.ALL на стороне @OneToMany. - person mvmn; 31.03.2017

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

Цитировать:

CascadeType.PERSIST: при сохранении сущности также сохраняются сущности, содержащиеся в ее полях. Мы предлагаем либеральное применение этого правила каскада, потому что, если EntityManager находит поле, которое ссылается на новую сущность во время сброса, и поле не использует CascadeType.PERSIST, это ошибка.

CascadeType.REMOVE: при удалении объекта он также удаляет объекты, содержащиеся в этом поле.

CascadeType.REFRESH: при обновлении объекта также обновите объекты, содержащиеся в этом поле.

CascadeType.MERGE: при объединении состояния объекта также объедините объекты, содержащиеся в этом поле.

Себастьян

person seba.wagner    schedule 23.10.2012
comment
Эта информация, впервые появившаяся в JPA, полезна, но как насчет Detach здесь? - person Sarz; 05.12.2014
comment
В CascadeType.DETACH при отсоединении объекта em также отсоединяют объекты, удерживаемые родительским объектом. - person Dorian Mejer; 04.06.2016

Вы не должны использовать CascadeType.ALL на @ManyToOne, поскольку переходы состояний сущностей должны распространяться от родительских сущностей к дочерним, а не наоборот.

Сторона @ManyToOne всегда является дочерней ассоциацией, поскольку она отображает нижележащий столбец внешнего ключа.

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

person Vlad Mihalcea    schedule 10.08.2017
comment
Спасибо, Влад, я не уверен, почему это не самый лучший ответ. - person Slava Imeshev; 05.05.2021

Из спецификации EJB3.0:

Использование каскадного элемента аннотации может использоваться для распространения эффекта операции на связанные объекты. Каскадная функциональность чаще всего используется в родительско-дочерних отношениях.

Если X - управляемый объект, операция удаления вызывает его удаление. Операция удаления выполняется каскадно для сущностей, на которые ссылается X, если отношения от X к этим другим сущностям аннотированы значением элемента аннотации cascade = REMOVE или cascade = ALL.

Итак, в двух словах, отношения сущностей, определенные с помощью CascadeType.All, будут гарантировать, что все события сохранения, такие как сохранение, обновление, слияние и удаление, происходящие в родительском элементе, будут переданы дочернему элементу. Определение других CascadeType параметров предоставляет разработчику более детальный уровень контроля над тем, как ассоциация сущностей обрабатывает сохраняемость.

Например, если у меня есть объект Book, содержащий список страниц, и я добавляю объект страницы в этот список. Если аннотация @OneToMany, определяющая связь между Книгой и Страницей, помечена как CascadeType.All, сохранение Книги приведет к тому, что Страница также будет сохранена в базе данных.

person Kevin Bowersox    schedule 23.10.2012

В JPA 2.0, если вы хотите удалить адрес, если вы удалили его из объекта User, вы можете добавить orphanRemoval=true (вместо CascadeType.REMOVE) в свой @OneToMany.

Дополнительное объяснение между orphanRemoval=true и CascadeType.REMOVE находится здесь.

person Emilien Brigand    schedule 06.08.2015

Если вы просто хотите удалить адрес, назначенный пользователю, и не влиять на класс сущности User, вам следует попробовать что-то вроде этого:

@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;
}

Таким образом, вам не нужно беспокоиться об использовании выборки в аннотациях. Но помните, что при удалении пользователя вы также удалите связанный адрес с объектом пользователя.

person szachMati    schedule 19.01.2019