Grails以一对一的关联替换对象

时间:2011-11-22 12:23:19

标签: java hibernate grails gorm

我有两个以下域名:

User {
   UserData userData
}

UserData {
   static belongsTo = [user: User]
}

并且在某些时候我想将两个用户合并为一个。我的意思是删除一个User实例并将userData附加到另一个用户。

我试过了:

User zombieUser
User liveUser

UserData data = zombieUser.userData
zombieUser.delete()
liveUser.userData = data
userData.user = liveUser
userData.save()
liveUser.save()

其实我尝试了不同的变种,不同的顺序,似乎所有可能的方式。但它总是失败,但有例外。当前代码将失败:

deleted object would be re-saved by cascade (remove deleted object from associations): [UserData#1]

如果我在zombie.delete()之后将*.save()置于最低点,我会得到:

Field error in object 'User' on field 'userData': rejected value [UserData : 1]; codes ... default message [Property [{0}] of class [{1}] with value [{2}] must be unique]

有没有办法将现有对象从一个对象重新连接到另一个对象?


工作代码:

UserData userData = zombieUser.userData

userData.user = null
zombieUser.userData = null
zombieUser.save(flush: true)
userData.save()

liveUser.userData = userData
userData.user = liveUser
liveUser.save()
userDate.save(flush: true)

2 个答案:

答案 0 :(得分:1)

问题在于,由于您的belongsTo声明,并且根据cascading rules,只要删除了userData,就会从数据库中删除zombieUser。调用liveUser.save()后,userData将再次保存。顺便说一下,您再次不需要致电userData.save(),因为此belongsTo声明,liveUser.save()会级联到userData

我看到两个选项来解决您的问题:

  1. 对新的userData 对象执行UserData的副本,并将此对象附加到liveUser,如下所示:

    withTransaction {
      UserData data = new UserData(prop: zombieUser.userData.prop)
      liveUser.userData = data
      zombiUser.delete()
      liveUser.save()
    }
    

    删除zombieUser时,将通过级联删除旧的UserData对象,并在保存liveUser时创建一个新的。

  2. belongsTo移除userData您将不再受益于级联,并且必须自行管理保存userData,并制作如果没有user.userData引用它,请确保从数据库中删除user(不要忘记为此进行交易,如同您多次调用savedelete时一样在你的方法中。)

  3. 您选择哪种方法取决于您的对象的耦合程度。通常情况下,如果它们非常耦合,您将受益于级联(通过belongsTo)并且可能会为1.如果它们不是非常耦合(即可能有多个用户具有相同的userData),那么{{ 1}}错了,你应该选择方法2.

    如果您的GORM模型具有复杂的依赖关系,GORM gotchas中提供的概念将极大地帮助您。

答案 1 :(得分:0)

您需要向域类添加映射,以告诉它在删除对象时要执行的操作。例如,删除父项也应删除其所有子项??

static mapping = {
    userData cascade: "all-delete-orphan"
}