我有一个映射(只有重要部分):
<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表中的行)。有没有办法实现这个目标?
答案 0 :(得分:10)
Cascade适用于实体级别。由于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)
}
或者您可能希望用关联实体替换多对多映射,在这种情况下,您可以简单地使用级联。这样您就可以更轻松地向作业添加更多信息。例如,如果您必须表达“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