Hibernate多对多映射和cascade = delete

时间:2010-02-15 13:14:35

标签: java hibernate orm

我有一个映射(只有重要部分):

<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>

通过此映射,当我删除角色时,也会删除具有此角色的人员。我想要实现的是删除Role时删除关联(PERSON_ROLE表中的行)。有没有办法实现这个目标?

3 个答案:

答案 0 :(得分:10)

Cascade适用于实体级别。由于Person_Role未映射为实体,因此级联无法帮助您AFAIK。

您可以在从Person_RoleRole的外键上使用“级联删除”上的数据库级别。

或者你可以 - 正如sfussenegger指出的那样 - 以编程方式删除关联。请注意,由于您在两个实体上映射了关联,因此Person_Role中的每一行都会在对象模型中出现两次。在这种情况下,建议从两个集合中删除相关条目,以免破坏对象模型。但是,Hibernate只会在持久更改时查看未与inverse="true"映射的关联的结尾。也就是说,要从与当前映射的关联中删除,您必须从Person.roles删除,而不是Role.assignments

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

或者您可能希望用关联实体替换多对多映射,在这种情况下,您可以简单地使用级联。这样您就可以更轻松地向作业添加更多信息。例如,如果您必须表达“Joe在QA上工作30%,在需求工程师中工作70%”,您只需将该字段添加到关联中即可。

答案 1 :(得分:1)

为什么不在删除角色之前简单地调用role.getAssignments().clear()

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

我不是cascade="delete"的忠实粉丝。每当我想到一段XML能够删除整个有价值数据表时,我就会感到这种奇怪的直觉:)

答案 2 :(得分:0)

根本不要在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