JPA @ManyToOne с CascadeType.ALL
Я думаю, что неправильно понял значение каскадирования в контексте отношения @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
, я думаю)?
Ответы
Ответ 1
Значение CascadeType.ALL
заключается в том, что постоянство будет распространять (каскадно) все операции EntityManager
(PERSIST, REMOVE, REFRESH, MERGE, DETACH
) на связанные объекты.
В вашем случае кажется плохой идеей, так как удаление Address
приведет к удалению связанного User
. Поскольку пользователь может иметь несколько адресов, другие адреса станут сиротами. Однако обратный случай (аннотирование User
) имел бы смысл - если адрес принадлежит только одному пользователю, безопасно распространять удаление всех адресов, принадлежащих пользователю, если этот пользователь удален.
BTW: вы можете добавить атрибут mappedBy="addressOwner"
к вашему User
, чтобы сигнализировать поставщику персистентности, что столбец соединения должен находиться в таблице ADDRESS.
Ответ 2
См. здесь для примера из документов OpenJPA. CascadeType.ALL
означает, что он выполнит все действия.
Цитата:
CascadeType.PERSIST: при сохранении сущности также сохраняются сущности, хранящиеся в этом поле. Мы предлагаем либеральное применение этого правила каскада, потому что если EntityManager находит поле, которое ссылается на новый объект во время флеша, и поле не использует CascadeType.PERSIST, это ошибка.
CascadeType.REMOVE: при удалении объекта также удаляются сущности, хранящиеся в этом поле.
CascadeType.REFRESH: при обновлении объекта также обновляйте объекты, содержащиеся в этом поле.
CascadeType.MERGE: при объединении состояния объекта также объединяются объекты, содержащиеся в этом поле.
Себастьян
Ответ 3
Из спецификации EJB3.0:
Использование элемента каскадной аннотации может использоваться для распространения эффект операции для ассоциированных объектов. Каскад функциональность наиболее обычно используется в отношениях родитель-потомок.
Если X - управляемый объект, операция удаления заставляет его становиться удален. Операция удаления каскадируется для объектов, на которые ссылается X, если отношения от X к этим другим объектам аннотируются с помощью значение каскада = REMOVE или каскад = ВСЕ значение элемента аннотации.
Таким образом, отношения сущностей, определенные с помощью CascadeType.All
, гарантируют, что все дочерние события, такие как сохранение, обновление, слияние и удаление, которые происходят у родителя, будут переданы дочернему элементу. Определение других опций CascadeType
предоставляет разработчику более гранулированный уровень контроля над тем, как ассоциация сущностей обрабатывает постоянство.
Например, если у меня была объектная книга, содержавшая список страниц, и я добавляю объект страницы в этот список. Если аннотация @OneToMany
, определяющая связь между книгой и страницей, помечена как CascadeType.All
, сохранение Книги приведет к тому, что страница также будет сохранена в базе данных.
Ответ 4
Как я объяснил в этой статье и в моей книге " Высокопроизводительное постоянство Java", вы никогда не должны использовать CascadeType.ALL
для @ManyToOne
поскольку переходы состояний сущностей должны распространяться от родительских сущностей к @ManyToOne
.
@ManyToOne
всегда является @ManyToOne
ассоциацией, поскольку она должна отображать базовый FK.
Поэтому переместите CascadeType.ALL
из ассоциации @ManyToOne
в @OneToMany
которая должна использовать атрибут mappedBy
так как это наиболее эффективное отображение один-ко-многим. '
Ответ 5
В JPA 2.0, если вы хотите удалить адрес, если вы удалили его из пользовательского объекта, вы можете добавить orphanRemoval=true
(вместо CascadeType.REMOVE
) в свой @OneToMany
.
Больше объяснений между orphanRemoval=true
и CascadeType.REMOVE
здесь здесь.
Ответ 6
Если вы просто хотите удалить адрес, назначенный пользователю, и не влиять на класс сущности "Пользователь", попробуйте что-то вроде этого:
@Entity
public class User {
@OneToMany(mappedBy = "adressOwner", cascade = CascadeType.ALL)
protected Set<Address> userAddresses = new HashSet<>();
}
@Entity
public class Adresses {
@ManyToOne(cascade = CascadeType.REFRESH) @JoinColumn(name = "user_id")
protected User adressOwner;
}
Таким образом, вам не нужно беспокоиться об использовании fetch в аннотациях. Но помните, что при удалении пользователя вы также удаляете связанный адрес с объектом пользователя.
Ответ 7
удалить cascade = CascadeType.ALL из отношения