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 из отношения