After modifying an inherited many-to-one relationship field the change cannot be detected using isDirty()
or similar checks.
How can I detect the change without manually checking the field?
I have already attempted to use @DirtyCheck
, however this only works for simple fields, such as lookupId
.
@DirtyCheck
does not fix relationship fields, such as lookup
.
Utilizing:
- GORM without grails, specifically gorm-hibernate5-spring-boot:6.1.9.RELEASE.
- Groovy 2.4.15
- Java 8u151
The following test is passing and displays the current undesired behavior.
@Unroll
def 'MyObject dirty check with setter: #setter'() {
given: '2 existing Lookups and a newly created MyObject'
Lookup lookup1 = new Lookup(
code: 'CODE1'
).save(flush: true, failOnError: true)
Lookup lookup2 = new Lookup(
code: 'CODE2'
).save(flush: true, failOnError: true)
MyObject myObject = new MyObject(
name: 'someName',
lookup: Lookup.get('CODE1'),
).save(flush: true, failOnError: true)
when: 'change the lookup'
if(setter) {
myObject.setLookup(Lookup.get('CODE2'))
} else {
myObject.lookup = Lookup.get('CODE2')
}
then: 'we can manually detect the change'
myObject.lookup.code == 'CODE2'
myObject.getPersistentValue('lookup').code == 'CODE1'
myObject.getPersistentValue('lookup') != myObject.lookup
myObject.getPersistentValue('lookup').code != myObject.lookup.code
and: 'dirty checks do not detect the change'
false == (myObject.lookup.getDirtyPropertyNames() ||
myObject.getDirtyPropertyNames() ||
myObject.lookup.isDirty() ||
myObject.lookup.hasChanged() ||
myObject.hasChanged() ||
myObject.isDirty() ||
((LookupBase)myObject.lookup).isDirty() ||
((LookupBase)myObject.lookup).hasChanged() ||
((ModelBase)myObject).isDirty() ||
((ModelBase)myObject).hasChanged()
)
where:
setter << [false, true]
}
There is a parent class:
@ToString(includeNames=true)
@EqualsAndHashCode(
includes = [ 'lookup', 'lookupId', ]
)
@AutoClone
class ModelBase {
UUID id
Lookup lookup
String lookupId
}
And another parent class:
@ToString(includeNames=true)
@EqualsAndHashCode(
includes = [ 'code', ]
)
class LookupBase {
String code
static constraints = {
code nullable: false
}
static mapping = {
id name: 'code', generator: 'assigned'
}
}
A child class:
@Entity
@ToString(
includeNames=true,
includeSuperProperties=true,
excludes = [ ... ]
)
@EqualsAndHashCode(
callSuper = true,
excludes = [ ... ]
)
class MyObject extends ModelBase implements GormEntity<MyObject> {
String name
}
And another child class:
@Entity
@ToString(includeNames=true, includeSuperProperties=true)
@AutoClone
class Lookup extends LookupBase implements GormEntity<Lookup> {
static constraints = {
code maxSize: 20
}
}