Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check isDirty('transient_fieldName') for transient fields in Grails

Having a case in one of my domain class that we store a transient field to Mongo database in beforeInsert and afterUpdate hooks which works perfectly with following conditions:-

  • Inserts works well without any issue.
  • Updates works well if there is a modified non transient field

The problem is isDirty works for non-transient properties.

Code is as below:

class ResoruceInstance {
    def configurationService
    Status status

   //Transient
    Map<String, Object> configuration
    static transients = ['configuration']


    public Map<String, Object> getConfiguration() {
        if(!configuration)
            configuration =  configurationService.get(id, CollectionConstants.RESOURCE_INSTANCE_IDENTIFIER)

        return configuration
    }

    def afterInsert() {
        configurationService.save(id, CollectionConstants.RESOURCE_INSTANCE_IDENTIFIER, configuration)
     }
    def afterUpdate() {
        if(this.isDirty("configuration"))
            configurationService.save(id, CollectionConstants.RESOURCE_INSTANCE_IDENTIFIER, configuration)
     }

}

To handle this problem I created isDirtyMongo('transient_field'). This works well till the time a non-transient property is modified as afterUpdate is called only for transient properties.

Modified hook is as below:

def afterUpdate() {
            if(this.isDirtyMongo("configuration"))
                configurationService.save(id, CollectionConstants.RESOURCE_INSTANCE_IDENTIFIER, configuration)
         }

boolean isDirtyMongo(String property){
//return whether is dirty or not
}

So, the ultimate question is how can we call an update hook for transient field modifications as well.

Any help would be highly appreciated.

like image 286
Vinay Prajapati Avatar asked Jun 22 '15 05:06

Vinay Prajapati


1 Answers

Implement the Interceptor.findDirty:

public class TransientFieldDirtinessInterceptor extends EmptyInterceptor {
    @Override
    public int[] findDirty(Object entity, ..., String[] propertyNames, ...) {
        if ((entity instanceof EntityToCheck) && isTransientFieldDirty(entity)) {
            // Just return all fields as dirty
            int[] result = new int[propertyNames.length];
            for(int i = 0; i < result.length; i++) {
                result[i] = i;
            }
            return result;
        }
        // Use Hibernate's default dirty-checking algorithm
        return null;
    }
}

Basically, let Hibernate think that all fields are dirty if the transient field is dirty.

You could try to optimize this a little bit to mark just the first property as dirty (no matter how many of them are dirty, the entity is dirty if at least one property is dirty):

int[] result = new int[1];
result[0] = 0;
return result;

However, this will always exclude other properties from the SQL update statement if you use @DynamicUpdate for these entities, so I assume that the more clear and consistent way is to mark all properties as dirty (without @DynamicUpdate all properties are always included in the SQL update statement anyway).

like image 74
Dragan Bozanovic Avatar answered Nov 19 '22 07:11

Dragan Bozanovic