我正在使用Grails 1.3.7,并拥有以下域类:
package com.fxpal.test
class UserGroup {
String name
static constraints = {
name(blank: false)
}
}
class Invitation {
UserGroup group
String user
static belongsTo = [group: UserGroup]
static constraints = {
group(nullable: false)
}
}
我希望能够删除在删除该UserGroup实例时引用UserGroup实例的所有Invitation实例,而没有引用UserGroup中的Invitation的显式关系。换句话说,我希望从UserGroup到邀请进行级联删除,而不修改Group。
由于表示邀请的约束,我的测试失败了 - > UserGroup关系:
void testCascadingDelete() {
UserGroup group1 = new UserGroup(name: 'group1').save(flush: true, failOnError: true)
UserGroup group2 = new UserGroup(name: 'group2').save(flush: true, failOnError: true)
Invitation invitation = new Invitation(user:'user1', group: group1).save(flush: true, failOnError: true)
assertEquals("Wrong number of groups.", 2, UserGroup.count())
assertEquals("Wrong number of invitations.", 1, Invitation.count())
group1.delete(flush: true, failOnError: true)
assertEquals("Wrong number of groups.", 1, UserGroup.count())
assertEquals("Wrong number of invitations.", 0, Invitation.count())
}
当我运行测试时,它会像这样失败:
could not delete: [com.fxpal.test.UserGroup#1]; SQL [delete from user_group where id=? and version=?]; constraint [FK473F7799A8642225]; nested exception is org.hibernate.exception.ConstraintViolationException: could not delete: [com.fxpal.test.UserGroup#1]
org.springframework.dao.DataIntegrityViolationException: could not delete: [com.fxpal.test.UserGroup#1]; SQL [delete from user_group where id=? and version=?]; constraint [FK473F7799A8642225]; nested exception is org.hibernate.exception.ConstraintViolationException: could not delete: [com.fxpal.test.UserGroup#1]
at com.fxpal.test.InvitationIntegrationTests.testCascadingDelete(InvitationIntegrationTests.groovy:23)
Caused by: org.hibernate.exception.ConstraintViolationException: could not delete: [com.fxpal.test.UserGroup#1]
at com.fxpal.test.InvitationIntegrationTests.testCascadingDelete(InvitationIntegrationTests.groovy:23)
...
这似乎是规范的鼻子面部示例,但级联删除似乎不起作用。我真的不想在UserGroup中代表邀请,特别是因为最后,邀请将引用其他几个域类,删除其中任何一个类都会导致相应的邀请被删除。 / p>
我错过了什么?
基因
答案 0 :(得分:5)
我不确定在没有双向关系的情况下是否可能,但您可以在事务服务方法中轻松完成(以确保删除所有操作或不发生):
void deleteGroup(UserGroup group) {
Invitation.executeUpdate(
'delete from Invitation where group=:group',
[group: group])
group.delete(flush: true, failOnError: true)
}
然后您的测试成为
def fooService
...
void testCascadingDelete() {
UserGroup group1 = new UserGroup(name: 'group1').save(flush: true, failOnError: true)
UserGroup group2 = new UserGroup(name: 'group2').save(flush: true, failOnError: true)
Invitation invitation = new Invitation(user:'user1', group: group1).save(flush: true, failOnError: true)
assertEquals("Wrong number of groups.", 2, UserGroup.count())
assertEquals("Wrong number of invitations.", 1, Invitation.count())
fooService.deleteGroup group1
assertEquals("Wrong number of groups.", 1, UserGroup.count())
assertEquals("Wrong number of invitations.", 0, Invitation.count())
}
一些较小的无关注释 - 默认情况下属性不为null,因此您可以删除group(nullable: false)
约束。您在地图表单中的belongsTo
定义了该名称的变量,因此您可以省略UserGroup group
中的Invitation
。
更新:
另一个不太干扰的选项是使用UserGroup
中的删除前事件:
def beforeDelete() {
Invitation.executeUpdate(
'delete from Invitation where group=:group',
[group: this])
}