I have two following domains:
User {
UserData userData
}
UserData {
static belongsTo = [user: User]
}
and at some point I want to merge two users into one. I mean delete one instance of User and attache userData to another user.
I’ve tried:
User zombieUser
User liveUser
UserData data = zombieUser.userData
zombieUser.delete()
liveUser.userData = data
userData.user = liveUser
userData.save()
liveUser.save()
Actually I’ve tried different variants, different order, seems that all possible ways. But it always fails with an exceptions. Current code will fail with:
deleted object would be re-saved by cascade (remove deleted object from associations): [UserData#1]
If i’ve put zombie.delete() to bottom, after *.save(), I will get:
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]
Are there any way to reconnect existing object from one object to another?
Working code:
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)
The problem is that because of your
belongsTodeclaration, and according to cascading rules,userDatais deleted from the database as soon aszombieUseris deleted. WhenliveUser.save()is called,userDatawould be saved again. By the way, you call touserData.save()is not needed as again, because of thisbelongsTodeclaration,liveUser.save()is cascaded touserData.I see two options for solving your problem:
Perform a deep copy of
userDatato a newUserDataobject, and attach this object toliveUser, like this:The old UserData object will be deleted by cascade when deleting
zombieUserand a new one will be created when savingliveUser.Remove
belongsTofromuserData. You won’t benefit of cascading anymore, and will have to manage savinguserDatayourself, and make sureuser.userDatais deleted from the database when nouserreference it (don’t forget to make transactions for that, as always when you have several call tosaveordeletein your method).Which approach you choose depends on how coupled your objects are. Typically, if they are very coupled, you will benefit of cascading (through
belongsTo) and may go for 1. If they are not very coupled, (i.e. there may be several users with the same userData), thenbelongsTois wrong and you should choose approach 2.The concepts presented in GORM gotchas will greatly help you if you have a GORM model with complicated dependencies.