In Java projects we often face the following scenario… In a server application we read a set of associated objects from a database. For example:
This data is sent to a client application. A client application user might modify Band name, add some Instruments and then remove a Manager. Then a user clicks submit/proceed and we are supposed to store the state of the object graph into a database.
You would like to store only truly changed objects with the correct SQL operation. In some cases ORM tools could perhaps help us with smart cascade settings. However, we prefer specifically controlling insert/update/delete SQL operation (since our client can track what has happened and we don’t want to execute any additional SQL). So we have used the following pattern…
There is BaseEntity that all persistent objects extend:
public class BaseEntity {
// set true if entity needs to be deleted
private boolean deleted;
// set true if entity needs to be updated
private boolean changed;
// set true if entity needs to be inserted
private boolean newEntity;
// necessary get/setters...
In a client application we call methods setChanged(), setDeleted(), setNewEntity() in user event listeners. When objects need to be stored in a database, we can choose the appropriate SQL operation based on these flags. For example:
if (entity.isDeleted()) {
session.delete(entity);
} else if (entity.isNewEntity()) {
session.save(entity);
} else if (entity.isChanged()) {
session.update(entity);
}
The only trick here is to write code that iterates all objects found in an object graph. To avoid coding this manually for all object graphs, we have implemented a small helper class that uses reflection to do this. So all we need to code in an application is something like this:
daoHelper.persistWholeGraph(myBand);
This would investigate all BaseEntity objects found inside myBand. It checks Collections of course and finds out the correct order of SQL statements.
We have used this pattern with Hibernate. And if you have read about Kauklahti, you probably guessed by now, that it supports this pattern. All you need to do is implement OperationResolver, for example:
public class BaseEntityOperationResolver implements OperationResolver {
@Override
public Operation resolve(Object obj) {
if (obj instanceof BaseEntity) {
BaseEntity entity = (BaseEntity) obj;
if (entity.isNewEntity()) {
return Operation.INSERT;
} else if (entity.isDeleted()) {
return Operation.DELETE;
} else if (entity.isChanged()) {
return Operation.UPDATE;
}
}
return Operation.IGNORE;
}
So you can pass this resolver to Mapper.writeInsertUpdateDelete method. This writes the correct SQL operation for each Object in given object graph.
Generally, I am interested in to hear about other peoples experiences about this. What pattern has been good/bad in storing a client modified object graph? Does your ORM handle this well enough? What about if we needed to update only specific columns?
