可以在beforeDelete方法中清除多对多关系吗?

时间:2018-02-21 17:00:55

标签: grails gorm

示例项目:https://github.com/joemccall86/cascade-delete-test/tree/automatic-collection-purge

我不确定这是不是一个错误,因为我还没有看到它在任何地方工作的例子。

说我有以下域类:

class Organization {

    String name

    static hasMany = [
            users: Person,
            teams: Team
    ]

    static mapping = {
        users cascade: 'all-delete-orphan'
    }
}

class Person {

    String name
    Organization organization

    static belongsTo = [Organization, Team]
    static hasMany = [teams: Team]

    static constraints = {
    }

    def beforeDelete() {

        Team.withNewSession {
            removeFromAllTeams()
        }

        true
    }

    def removeFromAllTeams() {
        Team.where {
            members {
                id == this.id
            }
        }.each { Team team ->
            if (team.members.contains(this)) {
                team.members.remove(this)
                team.save()
            }
        }
    }
}


class Team {

    String name

    static hasMany = [members: Person]
    static belongsTo = [organization: Organization]

    static constraints = {
    }
}

根据https://spring.io/blog/2010/07/02/gorm-gotchas-part-2/(特别是关于多对多关系级联的部分),我需要在成功删除之前手动清除团队中的人员。这是通过方法removeFromAllTeams完成的。

每次我打算删除用户时都会手动调用它(这通常会发生在服务调用中),但它看起来更像是属于域对象本身的beforeDelete方法。但是当我把它放在那里时,我得到了:

SQL [n/a]; Referential integrity constraint violation: "FKGHKKY8WMH379RPMFH92T807RY: PUBLIC.TEAM_MEMBERS FOREIGN KEY(PERSON_ID) REFERENCES PUBLIC.PERSON(ID) (1)"; SQL statement:
delete from person where id=? and version=? [23503-194]; nested exception is org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FKGHKKY8WMH379RPMFH92T807RY: PUBLIC.TEAM_MEMBERS FOREIGN KEY(PERSON_ID) REFERENCES PUBLIC.PERSON(ID) (1)"; SQL statement:
delete from person where id=? and version=? [23503-194]

这是一个spock测试来说明我在做什么:

@Unroll
void "user is removed from team before deletion, runManually = #runManually"() {
    given: 'an existing org'
    Organization.withNewSession {
        def organization = new Organization(name: 'Cyberdyne Systems').save(failOnError: true)

        and: 'a person is added'
        organization.addToUsers(name: 'John Connor').save(failOnError: true)
        organization.save(failOnError: true, flush: true)

        and: 'a new team is added to the org'
        organization.addToTeams(name: 'IT').save(failOnError: true, flush: true)

        and: 'the person is added to the team'
        organization.teams.first().addToMembers(organization.users.first())
        organization.save(failOnError: true, flush: true)
    }

    and: 'the person is deleted'
    def userToDelete = Person.first()
    if (runManually) {
        userToDelete.removeFromAllTeams()
    }
    userToDelete.delete(flush: true)

    expect: 'the team has no users'
    Team.first().members.isEmpty()

    and: 'there are no more users'
    Person.count == 0

    where:
    runManually << [true, false]
}

我错过了什么?换句话说,是否有可能让域类在beforeDelete内进行自己的关系清理?

1 个答案:

答案 0 :(得分:0)

我在Grails 3.2.12和GORM 6.1.6.RELEASE中遇到过这个问题。

和您一样,我尝试将清理代码添加到beforeDelete方法,但它没有用。根据我的提交日志:

&#34;出于某种原因,这不能在beforeDelete中完成,可能是因为GORM在调用beforeDelete&#34;之前检查删除是否有效。

我建议您在GitHub上创建一个问题,并要求Grails团队澄清这是一个错误还是一个功能。