【问题标题】:Cascading deletes without bidirectional relationships in Grails在 Grails 中没有双向关系的级联删除
【发布时间】:2011-07-24 22:42:36
【问题描述】:

我使用的是 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 级联删除到 Invitation,而不修改 Group。

由于表示邀请 -> 用户组关系的约束,我对此的测试失败:

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 中表示邀请,特别是因为最后,邀请将引用其他几个域类,删除其中任何一个都会导致相应的邀请也被删除。

我错过了什么?

基因

【问题讨论】:

    标签: grails grails-orm cascading-deletes


    【解决方案1】:

    我不确定在没有双向关系的情况下是否可行,但您可以在事务服务方法中轻松地自己完成(以确保删除全部发生或不发生):

    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())
    }
    

    一些无关紧要的小注释 - 默认情况下属性不为空,因此您可以删除 group(nullable: false) 约束。并且像您一样以 Map 形式定义的 belongsTo 定义了该名称的变量,因此您可以在 Invitation 中省略 UserGroup group

    更新:

    另一个不那么侵入性的选项是使用UserGroup 中的删除前事件:

    def beforeDelete() {
       Invitation.executeUpdate(
          'delete from Invitation where group=:group',
          [group: this])
    }
    

    【讨论】:

    • 感谢您的快速回复,伯特!我希望避免使用 deleteGroup() 解决方案风格,因为这需要我确保 Invitation 可能用作其上下文的每个其他类都存在这种方法(例如,发出邀请的用户)。哦,好吧。
    • 至于复制belongsTo 中的属性,我故意这样做是为了让 SpringSource Tool Suite (Eclipse) 在进行语法辅助时识别我的类中的属性。
    • 我用更轻量级的选项更新了答案。仍然需要额外的代码,但它包含在域类中。
    • 我想知道是否希望能够声明这些语义,而不是编写beforeDelete() 方法。似乎所需的信息完全隐含在 Invitation 类中的单向 def static belongsTo = [group: UserGroup] 声明中。为 Grails 2.0 请求这个是否为时已晚?
    • 现在还不算太晚,但我不确定它会在优先列表中的哪个位置出现。我们本周将发布 2.0.0M1,并且可以在 RC 之前添加修复/增​​强功能。继续,JIRA。
    猜你喜欢
    • 1970-01-01
    • 2017-11-17
    • 1970-01-01
    • 2012-03-27
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多