Вопрос каскадный JPA - PullRequest
       15

Вопрос каскадный JPA

11 голосов
/ 08 октября 2009

У меня есть две сущности с именами User и UserProfile в моей модели данных. Вот как они отображаются.

Код от пользователя:

@OneToOne(cascade=CascadeType.ALL)
@PrimaryKeyJoinColumn
public UserProfile getUserProfile(){
    return this.userProfile;
}

public void setUserProfile(UserProfile userProfile){
    this.userProfile=userProfile;
}

Код от объекта UserProfile:

@OneToOne(mappedBy="userProfile",cascade=CascadeType.ALL)
public User getUser(){
    return this.user;
}

public void setUser(User user){
    this.user=user;
}

Как видите, у меня есть cascadetype.all для атрибута пользователя в UserProfile. Но когда я пытаюсь удалить сущность UserProfile, соответствующая сущность User все еще остается. (Когда я пытаюсь удалить сущность User, соответствующая сущность UserProfile удаляется.)

Вот мой вопрос: -

  • Каскады действуют только тогда, когда я указываю их для объекта, которому принадлежат отношения?

Ответы [ 4 ]

16 голосов
/ 08 октября 2009

Ваш вопрос неверен сам по себе, отсюда и вся путаница. Артур хорошо поработал над своим ответом, но из комментариев ясно, что путаница все еще остается, поэтому позвольте мне остановиться здесь.

Каскады держатся только когда я указываю они на сущности, владеющей отношения?

"Каскад" - это атрибут, который вы указываете на одном (или, возможно, на обоих в случае двунаправленного) конца отношения. Он определяет, какие действия , выполненные на , которые конец будут распространяться на другой конец. Существует много различных типов этих действий, определенных в JPA, и , еще больше , определенных в расширениях Hibernate. Это различие важно - вам следует говорить только о распространяемом специфическом поведении, а не о "каскадном" в целом.

PERSIST, MERGE, REFRESH распространяются нормально (с конца, на котором они были объявлены, другому).

УДАЛИТЬ, однако, сложно, потому что это может означать две разные вещи. Если у вас есть отношения между A и B , и вы пытаетесь удалить A , вы можете удалить B на другом конец ИЛИ вы можете удалить ассоциацию , но оставить B без изменений. Hibernate проводит четкое различие между ними - вы можете объявлять каскадные типы REMOVE (DELETE) и DELETE_ORPHAN отдельно; JPA спецификации нет. Обратите внимание, что DELETE_ORPHAN не поддерживается для однозначных отношений (OneToOne / ManyToOne).

Таким образом, распространение REMOVE (само по себе или когда оно является частью ALL) зависит от того, есть ли у отношения явный владелец (однонаправленный всегда есть; двунаправленный имеет, если он отображается с помощью mappedBy и делает нет, если он сопоставлен с помощью таблицы соединений ), в этом случае он распространяется от владельца к владельцу ИЛИ нет владельца, и в этом случае он распространяется в любом направлении, но без семантики DELETE_ORPHAN, если это не было явно указано. Типичным примером последнего является двунаправленный «многие ко многим».

4 голосов
/ 08 октября 2009

Как сказал

Когда я пытаюсь удалить объект UserProfile, соответствующий объект User по-прежнему остается

Может быть, когда вы пытаетесь удалить UserProfile, вы получаете нарушение ограничения целостности из базы данных - используете ли вы MyISAM в MySQL?

Но так как ты ничего не говорит об этом. Возможно, ваша сущность UserProfile не имеет ссылки на сущность User.

Как сказано в спецификации JPA

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

Что-то вроде

UserProfile up = entityManager.find(UserProfile.class, id);

entityManager.close();

// Notice User is null outside a persistence context 
// So user will be not removed from the database because UserProfile does not have a reference to it
up.setUser(null);

entityManager.getTransaction().begin();

entityManager.remove(up);

entityManager.getTransaction().commit();

или у вас есть что-то вроде

entityManager.getTransaction().begin();

UserProfile up = entityManager.find(UserProfile.class, id);

// throws UPDATE USER_PROFILE SET USER_ID = NULL
up.setUser(null);

// up.getUser() is null
// So user is not removed
entityManager.remove(up);

entityManager.getTransaction().commit();

В ответ на комментарий ChhsPly:

В Java Persistence с книгой Hibernate вы видите следующее

Атрибут каскада является направленным: Он применяется только к одному концу ассоциации .

Я думаю, что было бы лучше, как

Применяется только к одному концу ассоциации за операцию

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

Атрибут mappdeBy устанавливает двунаправленное отношение . Атрибут mappedBy обозначил объект Address как обратную сторону отношения. Это означает, что сущность «Клиент» является владельцем отношений.

ChssPly прав, когда говорит, что mappedBy не имеет ничего общего с каскадом

1 голос
/ 08 октября 2009

Это правильно, когда у вас двунаправленные отношения, владелец диктует правила каскадирования, поскольку он является «владельцем». «Собственный» объект по сути следует приказам, он не может отдавать приказы - так сказать.

0 голосов
/ 02 июля 2014

В JPA 2.x, если вы хотите удалить каскад, используйте атрибут orphanRemoval:

@OneToMany(orphanRemoval=true)

см. Документацию здесь для получения дополнительной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...