I am not sure if this is a bug or the intended behaviour but I am quite
sure the documentation does not talk about it. @Walter can you please give
it a look?
I've used AI to summarize the findings.
*GORM/Hibernate does not detect changes to inherited properties during
dirty checking.*
The property is correctly persisted if another property of the entity is
modified at the same time, or if markDirty() is explicitly called. However,
changing only the inherited property does not result in an UPDATE being
issued.
Expected behavior
Changing a persistent property should mark the entity as dirty and cause
the property to be persisted when calling:
obj.save(flush: true)
Actual behavior
The entity is not considered dirty when only an inherited property is
changed.
For example:
TPaymentMethod obj = TPaymentMethod.get(id)
obj.dateDisabled = LocalDateTime.now()
obj.usernameDisabled = 'TEST'
println obj.isDirty()
println obj.isDirty('dateDisabled')
println obj.isDirty('usernameDisabled')
obj.save(flush: true, failOnError: true)
The output is:
dirty=false
dirty date=false
dirty username=false
No SQL UPDATE is generated and the values are not persisted.
However, if another property declared directly on TPaymentMethod is changed:
obj.description = obj.description + ' TEST'
obj.dateDisabled = LocalDateTime.now()
obj.save(flush: true, failOnError: true)
the entity is detected as dirty and both changes are persisted correctly.
Explicitly marking the entity as dirty also works:
obj.dateDisabled = LocalDateTime.now()
obj.usernameDisabled = 'TEST'
obj.markDirty()
obj.save(flush: true, failOnError: true)
Minimal exampleBase class
abstract class SystemManaged {
Long id
Long version
LocalDateTime dateCreated
LocalDateTime lastUpdated
LocalDateTime dateDeleted
LocalDateTime dateDisabled
String usernameCreated
String usernameUpdated
String usernameDeleted
String usernameDisabled
static constraints = {
id nullable: true
version nullable: true
dateCreated nullable: true
lastUpdated nullable: true
dateDeleted nullable: true
dateDisabled nullable: true
usernameCreated nullable: true
usernameUpdated nullable: true
usernameDeleted nullable: true
usernameDisabled nullable: true
}
}
Domain class
@GrailsCompileStatic
class TPaymentMethod extends SystemManaged
implements GormEntity, MultiTenant<TPaymentMethod> {
String description
static constraints = {
description nullable: false
}
}
Reproduction
@Transactional
void test(Long id) {
TPaymentMethod obj = TPaymentMethod.get(id)
obj.dateDisabled = LocalDateTime.now()
obj.usernameDisabled = 'TEST'
println "dirty=${obj.isDirty()}"
println "dirty dateDisabled=${obj.isDirty('dateDisabled')}"
println "dirty usernameDisabled=${obj.isDirty('usernameDisabled')}"
println "dirty properties=${obj.dirtyPropertyNames}"
obj.save(flush: true, failOnError: true)
}
Observed result:
dirty=false
dirty dateDisabled=false
dirty usernameDisabled=false
dirty properties=[]
No UPDATE is generated.
But this works:
obj.description = 'changed'
obj.dateDisabled = LocalDateTime.now()
obj.save(flush: true, failOnError: true)
And this also works:
obj.dateDisabled = LocalDateTime.now()
obj.markDirty()
obj.save(flush: true, failOnError: true)
Gianluca Sartori
--
https://dueuno.com