kaleidos / grails-postgresql-extensions

Grails plugin to use postgresql native elements such as arrays, hstores,...
Apache License 2.0
78 stars 63 forks source link

automatic dirty checking not working on array type #106

Open nicsl0s opened 7 years ago

nicsl0s commented 7 years ago

In a grails app I have a domain class like this:

class User {
         String[] privileges = ['JUNIOR_BIZDEV','TECHNICAL_ADMIN']

         Set<String> getPrivilegesSet() {
                return privileges.collect {it } as Set<String>
         }

        // convenience method to modify the user privileges
        void addToPrivilegesSet(String privilege) {
               def tmp = privilegesSet
               tmp.add(privilege)
               privileges = tmp.collect { it } as String[]
        }
}

// calling user somewhere
def user = User.get(SOME_ID)
user.addToRoleSet('JUNIOR_SOMETHING_ADMIN') // this causes the privileges to be dirty and the user got saved with a further role
user.save()

This used to work when using: org.grails.plugins:postgresql-extensions:4.6.2 grails version 3.2.8 gorm version 6.0.9.RELEASE

This stopped working when using: grails version 3.2.9 gorm version 6.1.4.RELEASE

I think the reason is some change in the new gorm version. It stops working since version gorm 6.1.0 Also using the org.grails.plugins:postgresql-extensions:5.1.0 did not change it. The workaround was to add a markDirty() in the convenience method:

  void addToPrivilegesSet(String privilege) {
               def tmp = privilegesSet
               tmp.add(privilege)
               privileges = tmp.collect { it } as String[]
               markDirty('privileges')
        }

Any Hints? Thx

jglapa commented 7 years ago

Don't have an answer but I recently discovered and fixed a similar dirty checking issue with hstore type in this plugin. Perhaps you could read my explanation notes and debug it the same way? -> https://github.com/kaleidos/grails-postgresql-extensions/pull/104#issue-229797446

It might give you some hints where the dirty checking mechanism fails. Looking at the definition of ArrayType here and the deepCopy method implementation https://github.com/kaleidos/grails-postgresql-extensions/blob/master/src/main/groovy/net/kaleidos/hibernate/usertype/ArrayType.java#L70

I would say that if something changed in Hibernate that it now compares by reference and not value the indeed this would explain your problem. And your fix of course helps because you are creating a completely new array.

ilopmar commented 7 years ago

Hi.

Dirty-checking has changed and been improved on Gorm 6.1. You can see an explanation by Graeme on how it works here: https://github.com/grails/grails-data-mapping/issues/961

igorrosenberg commented 7 years ago

I have observed the same missing drty-checking on Map types (JSON). As a temporary work-around, I forcibly modify another field of the Domain instance to make sure the save is performed :

domain.mapField.a  = 1 // some appended/updated data in domain.mapField
domain.dateCreated = new Date(domain.dateCreated.time+1) // dateCreated modification is an ugly workaround to the dirty-checking failure  
domain.save()
mhuebner commented 7 years ago

I also encountered this issue. Setting a Map property via setter internally calls markDirty but when using leftShift operator to add add some stuff to the map this would not work.

def additionalMapData = ['foo':'baar']
persistedInstance.mapProperty << additionalMapData 
animator013 commented 6 years ago

Have also the same problem with Gorm 6.1.x. Also with Map type.

mhuebner commented 6 years ago

If you want a collection to be dirty checked you will have to call the setter or manually set markDirty() on the instance. I am using the first variant so I have not too much framework-specific code within my classes.