Отображение Hibernate многие-ко-многим и каскад = удаление - PullRequest
3 голосов
/ 15 февраля 2010

У меня есть отображение (только важные части):

<class name="xyz.Role" table="ROLE" lazy="true">
  <id name="id" type="java.lang.Integer">
    <column name="ROLE_ID"/>
    <generator class="increment"/>
  </id>
  <set name="assignments" lazy="true" table="PERSON_ROLE" cascade="delete" 
inverse="true">
    <key column="ROLE_ID" />
    <many-to-many class="xyz.Person" column="PERSON_ID" />
  </set> 
</class>

и

<class name="xyz.Person" table="PERSON" lazy="true">
  <id name="Id" type="java.lang.Integer">
    <column name="TPP_ID"/>
    <generator class="increment"/>
  </id>

  <set name="roles" lazy="true" table="PERSON_ROLE" cascade="save-update">
    <key column="PERSON_ID" />
    <many-to-many class="xyz.Role" column="ROLE_ID" />
  </set> 
</class>

При таком сопоставлении, когда я удаляю роль, сам человек с этой ролью также удаляется. Чего я хотел бы добиться, так это удалить ассоциацию (строку из таблицы PERSON_ROLE) при удалении роли. Есть ли способ добиться этого?

Ответы [ 3 ]

10 голосов
/ 15 февраля 2010

Каскад работает на уровне сущностей. Поскольку Person_Role не отображается как сущность, каскад не может помочь вам AFAIK.

Вы можете использовать уровень базы данных "при каскадном удалении" для внешнего ключа от Person_Role до Role.

Или вы можете - как указывает sfussenegger - программно удалить связь. Обратите внимание, что, поскольку вы сопоставили связь для обеих сущностей, каждая строка в Person_Role будет дважды отображаться в вашей объектной модели. В таких случаях рекомендуется удалить соответствующие записи из обеих коллекций, чтобы не повредить вашу объектную модель. Однако Hibernate при сохранении изменений будет смотреть только на конец ассоциации, который не сопоставлен с inverse="true". То есть, чтобы удалить из ассоциации с вашим текущим отображением, вы должны удалить из Person.roles, а не Role.assignments:

for (Person p : role.assignments) {
    person.roles.remove(role)
}

Или вы можете заменить отображение «многие ко многим» на объект ассоциации, в этом случае вы можете просто использовать каскад. Это позволит вам более легко добавлять больше информации в назначения. Например, если вам нужно было выразить «Джо работает 30% на контроле качества и 70% инженером по требованиям», вы можете просто добавить это поле в ассоциацию.

1 голос
/ 15 февраля 2010

Почему бы просто не позвонить role.getAssignments().clear() перед удалением роли?

for (Person p : role.getAssignments()) {
    person.getRoles.remove(role)
}
role.getAssignments.clear();
session.delete(role);

Я не большой поклонник cascade="delete". Я чувствую эту странную интуицию всякий раз, когда думаю о фрагменте XML, который может удалить целые таблицы ценных данных:)

0 голосов
/ 15 февраля 2010

Не ставьте отображение на сторону Role вообще. Если вам в конечном итоге понадобится эта информация, получите ее с помощью запроса HQL. То есть избавиться от этого:

<set name="assignments" lazy="true" table="PERSON_ROLE" cascade="delete" 
    inverse="true">
    <key column="ROLE_ID" />
    <many-to-many class="xyz.Person" column="PERSON_ID" />
</set>

И всякий раз, когда вам нужны люди для роли (что, я думаю, должно быть редко), получите ее по:

SELECT p FROM Person p JOIN p.roles WHERE role=:role
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...