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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With