简体   繁体   English

Hibernate多对多映射和cascade = delete

[英]Hibernate many-to-many mapping and cascade=delete

I have a mapping (only important parts): 我有一个映射(只有重要的部分):

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

and

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

With this mapping, when I delete a role, very person with this role is also deleted. 使用此映射,当我删除角色时,也会删除具有此角色的人员。 What I would like to achieve, is delete the association (row from PERSON_ROLE table) when I delete Role. 我想要实现的是删除Role时删除关联(PERSON_ROLE表中的行)。 Is there any way to achieve this? 有没有办法实现这个目标?

Cascade works on the level of entities. Cascade适用于实体级别。 Since Person_Role is not mapped as entity, cascade can not help you AFAIK. 由于Person_Role未映射为实体,因此级联无法帮助您AFAIK。

You might use a database-level "on cascade delete" on the foreign key from Person_Role to Role . 您可以在从Person_RoleRole的外键上使用数据库级“on cascade delete”。

Or you can - as sfussenegger points out - remove the association programatically. 或者你可以 - 正如sfussenegger指出的那样 - 以编程方式删除关联。 Note that since you mapped the association on both entities, every row in Person_Role will appear twice in your object model. 请注意,由于您在两个实体上映射了关联,因此Person_Role每一行都将在对象模型中出现两次。 In such cases, it is recommended to remove the relevant entries from both collections in order not to corrupt your object model. 在这种情况下,建议从两个集合中删除相关条目,以免破坏对象模型。 Hibernate however will only look at the end of the association that is not mapped with inverse="true" when persisting changes. 然而,Hibernate只会在持久化更改时查看未使用inverse="true"映射的关联的结尾。 That is, to delete from the association with your current mapping, you must delete from Person.roles , not Role.assignments : 也就是说,从你的当前映射的关联删除,必须从删除Person.roles ,不Role.assignments

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

Or you might wish to replace the many-to-many mapping with an association entity, in which case you could simply use cascade. 或者您可能希望用关联实体替换多对多映射,在这种情况下,您可以简单地使用级联。 This would allow you to add more information to assignments more easily. 这样您就可以更轻松地向作业添加更多信息。 For instance, if you had to express "Joe works 30% on QA and 70% as requirements engineer", you could simply add that field to the association. 例如,如果您必须表达“Joe在QA上工作30%,在需求工程师中工作70%”,您可以简单地将该字段添加到关联中。

Why not simply call role.getAssignments().clear() before deleting the role? 为什么不在删除角色之前简单地调用role.getAssignments().clear()

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

I'm not a big fan of cascade="delete" . 我不是cascade="delete"忠实粉丝。 I get this weird gut feeling any time I think about a snippet of XML being able to delete entire tables of valuable data :) 每当我想到一段XML能够删除整个有价值数据表时,我就会感到这种奇怪的直觉感觉:)

Don't put a mapping on the Role 's side at all. 根本不要在Role方面放置映射。 If you eventually need this information, get it with an HQL query. 如果您最终需要此信息,请使用HQL查询获取此信息。 Ie get rid of this: 即摆脱这个:

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

And whenever you need the persons for a role (which I think should be rare) get it by: 无论何时你需要角色的人(我认为应该是罕见的)通过以下方式获得:

SELECT p FROM Person p JOIN p.roles WHERE role=:role

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM