Search code examples
grailsgroovymergegrails-orm

merge two domain objects and reassign children to one of them in Grails


I have two entries in a domain entity that I want to merge. Let's call the parent House and the children Room. I have a situation where I want to merge two House domains that are actually the same. I have the logic to do this top level merge.

However, I want to know if there is a way in Grails to easily say, 'go through the domain objects and wherever there is a fk pointer to House, update that fk to a new value'.

The code would be something like this

houseInst1.magicMerge(houseInst2)

This would run the House merge as well as check for every domain object that has a pointer (fk) to House and update where it points to houseInst2 originally to point to houseInst1.

Update: One key feature is that I'd like this to work if someone adds another domain object with a link to the master object. eg. if someone added Mortgages later, I don't want to update all my merge logic, it should go and find that Mortgages is a child of House, and update accordingly.


Solution

  • Grails domain objects expose the hibernate merge() method, but this does something completely different: it merges a (possibly detached) object back into the persistence context.

    I'm not aware of any built in functionality to merge two objects like you describe. I think you need to manually update the foreign keys as in Gregg's answer. A more efficient way to do the update would be through HQL like so:

    Room.executeUpdate('update Room set house = :newHouse where house = :oldHouse',
        [newHouse: newHouse, oldHouse: oldHouse])
    

    Edit: to automatically update all the associations, you can interrogate the Artefact:

    def artefact = grailsApplication.getArtefact("Domain", "House")
    artefact.associationMap.values().each { associationClass ->
        associationClass.executeUpdate("update ${associationClass.simpleName} set house = :newHouse where house = :oldHouse",
            [newHouse: newHouse, oldHouse: oldHouse])
    }