Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update "lastUpdated" Field in Parent Domain Class in Grails

I have a parent domain class the has a hasMany of another domain class. Both the parent and the child domain classes have the lastUpdated and the dateCreated fields. My issue is that when I update a child domain class, I need the parent domain class to reflect that change and update its lastUpdated field as well.

Is there any mapping or other configuration between the parent and child that Grails provides that would implement this feature?

Update

I added the following lines to the child domain class:

def beforeUpdate = {
    parent.lastUpdated = new Date()
}

I also had to make sure in the controller that when I updated a child, I also had to save the parent as well to persist the new lastUpdated field. This seems to work fine, but I would still like to know if there is a mapping or something similar that would do this.

like image 910
anthonylawson Avatar asked Jun 26 '12 16:06

anthonylawson


2 Answers

I have a feeling your suggested implementation will be buggy. You're updating the parent by setting the lastUpdated date manually, which might cause grails to update lastUpdated again after it does dirty checking on it. If that's the case, you would actually end up with a lastUpdated time that occurred after the date you original set. In your testing, this might be only a few (milli)seconds, but you can't guarantee that.

Not only that, but your implementation is harder to maintain since you have increased the coupling of Parent and Child.

Might I suggest another implementation? The lastUpdated field is supposed to represent the time the specific domain object was updated. The date you're looking for is not quite the same thing, so I wouldn't try to use the existing convention in the "wrong" way. It sounds like the date you want for the parent object is "the last time a child was modified".

Use a formula instead.

To do that, you could use a formula. With a formula, you get exactly what you want without having to directly modify the parent object, and you can still use dynamic finders and other Grails sugar.

class Parent {
    ...
    Date lastChildUpdated

    static hasMany = [ children: Child ]

    static mapping = {
        ...
        lastChildUpdated formula: '(SELECT max(c.last_updated) FROM child c WHERE c.parent_id = id)'
    }
}

GORM will load the value of the formula in whenever you read the object from the database. Now, whenever you save a Child, the parent will have an accurate value for that property without having to touch the Parent.

like image 76
A.J. Brown Avatar answered Sep 19 '22 20:09

A.J. Brown


I used a hack. I have added a Long updateTrigger field to my parent domain class and a touch method:

class Parent {
    Long updateTrigger

    static mapping = {
        autoTimestamp true
    }

    static constraints = {
        updateTrigger(nullable:true)
    }

    public touch() {
        if (updateTrigger == null) updateTrigger = 0
        updateTrigger++
        this
    }

In the update/save actions of the child controller, I just call:

child_instance.save() // save the child
child_instance.parent.touch().save() // updates parent's time stamp

This will increment the updateTrigger value, and the save() will automatically update the lastUpdated field thanks to the autoTimestamp set to true in the mapping. updatedTrigger is set to be nullable so that it doesn't invalidate any existing database table and therefore can be added anytime to any domain class.

like image 26
sebnukem Avatar answered Sep 22 '22 20:09

sebnukem