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:-
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.
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).
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