-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: Select Before Update, DB Snapshots and flushing behavior
PostPosted: Wed Nov 14, 2007 2:11 pm 
Expert
Expert

Joined: Sat Jan 17, 2004 2:57 pm
Posts: 329
Location: In the basement in my underwear
Hibernate version: 3.2.5

Name and version of the database you are using: Oracle 10g

I'm seeing some behavior that I'm not sure is by design with db snapshots and flushing.

We've got a custom persister that attempts to keep track of individual changes to our entities through the use of an 'originalValues' map that gets updated via property changes on the entity itself. It uses that map to determine a db snapshot to determine what properties need to be updated.

The 2 methods on the persister are as follows

Code:
    public Object[] getDatabaseSnapshot(Serializable id, SessionImplementor session) throws HibernateException {
        HibernateDomainObject entity = (HibernateDomainObject) session.getEntityUsingInterceptor(new EntityKey(id, this, session.getEntityMode()));
        Map originalValues = entity.getOriginalValues();
        Type[] types = getPropertyTypes();
        String[] propertyNames = getPropertyNames();
        Object[] values = new Object[propertyNames.length];
        boolean[] includeProperty = getPropertyUpdateability();
        for (int i = 0; i < propertyNames.length; i++) {
            if (includeProperty[i]) {
                if (originalValues.containsKey(propertyNames[i])) {
                    values[i] = types[i].disassemble(originalValues.get(propertyNames[i]), session, null);
                } else {
                    values[i] = types[i].disassemble(getPropertyValue(entity, propertyNames[i], session.getEntityMode()), session, null);
                }
            }
        }
        return values;
    }

    public boolean isSelectBeforeUpdateRequired() {
        return true;
    }


The isSelectBeforeUpdateRequired will force the snapshot to be used when checking for modified data and that all seems to work (been using it for years now)

However, we're looking at beefing up our Auditing in the interceptor and I noticed a bug on our side of things where I wasn't clearing our originalValues in the right spot. I was doing it in the postFlush on the interceptor but it seemed to me that we ended up processing the same records multiple times in the flush so I added it to the finally block. Our onFlushDirty looks like this:

Code:
    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException {
        try {
            if (entity instanceof Auditable && !((HibernateDomainObject) entity).getOriginalValues().isEmpty()) {
                for (int i = 0; i < propertyNames.length; i++) {
                    if (Auditable.AUDITABLE_AUDIT_INFO_PROPERTY.equals(propertyNames[i])) {
                        AuditInfo ai = ((Auditable) entity).getAuditInfo();
                        AuditInfo newAuditInfo = new AuditInfo(ai.getCreateDate(), ai.getCreateUser(), new Timestamp(System.currentTimeMillis()), getUserName());
                        //need to update the current state so that the changes will get persisted
                        currentState[i] = newAuditInfo;
                        ((Auditable) entity).setAuditInfo(newAuditInfo);
                        return true;
                    }
                }
            }
            return false;
        }
        finally {
            ((HibernateDomainObject) entity).markUnchanged();
        }
    }


An additional change I made in regards to the finally block was to also set the auditInfo directly in addition to returning the value in the currentState as I found I kept getting into the same block afterwards with the auditInfo being the only value changed as it seems to call the setter somewhere after the onFlushDirty call.

What I'm finding now is that onFlushDirty happens, my auditInfo is set, the changes I'm tracking get cleared but I am seeing the same entity come through again with no tracked changes, i.e. it gets to the return false line.

As far as I can tell it is because later on when the object is checked for dirtyness it uses a cached value of the db snapshot in which it thinks the object is still dirty and processes it again. The changes I just made to our side of things won't update the audit info again but it still will fire an update since it thinks it is dirty.

I guess my bottom line question is:
After the flush occurs, should the snapshot either be updated to reflect the current state of the entity or maybe even cleared so that the persister can determine if the object is truly dirty?

_________________
Some people are like Slinkies - not really good for anything, but you still can't help but smile when you see one tumble down the stairs.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.