级联删除Grails中没有双向关系

时间:2011-07-24 22:42:36

标签: grails gorm cascading-deletes

我正在使用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>

我错过了什么?

基因

1 个答案:

答案 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])
}