I'm working on a JpaMergeEventListener to clean the dirty-Flag on unchanged collections:
public class MyIntegrator implements Integrator { public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { EventListenerRegistry listenerRegistry = serviceRegistry.getService(EventListenerRegistry.class); listenerRegistry.setListeners(EventType.MERGE, new MyMergeEventListener()); } public void integrate(MetadataImplementor metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { // TODO Auto-generated method stub } public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { // TODO Auto-generated method stub } private static class MyMergeEventListener extends JpaMergeEventListener { private List<PersistentCollection> cleanCollections = new ArrayList<PersistentCollection>(); @Override protected void copyValues(EntityPersister persister, Object entity, Object target, SessionImplementor source, Map copyCache) { Object[] origValues = persister.getPropertyValues(entity); Object[] targetValues = persister.getPropertyValues(target); Type[] types = persister.getPropertyTypes(); // get Collections to be marked as clean // Do this BEFORE copyValues() is called, afterwards targetValues will be updated for (int i = 0; i < types.length; i++) { if (types[i].isCollectionType()) { checkCollection((Collection) origValues[i], (PersistentCollection) targetValues[i]); } } super.copyValues(persister, entity, target, source, copyCache); // Reset the dirtyFlag of unmodified collections for (PersistentCollection col : cleanCollections) { col.clearDirty(); } } private void checkCollection(Collection origValue, PersistentCollection targetValue) { Collection target = (Collection) targetValue.getValue(); if (origValue.size() != target.size()) { return; } if (origValue.size() == 0 && target.size() == 0) { return; } if (origValue.containsAll(target)) { cleanCollections.add(targetValue); } } } }