views:

747

answers:

2

Hi

I have a process which updates a tree to the database, and in doing so, performs reads to check for duplicates entities.

I'm finding that trying to do a criteria.uniqueResult() midway through this process causes the following error:

org.hibernate.PropertyValueException: not-null property references a null or transient value

Digging through the stack trace, I see that the uniqueResult() is flushing the session, attempting to perform updates that aren't ready to go to the database yet.

at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:996)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1589)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:306)
at org.hibernate.impl.CriteriaImpl.uniqueResult(CriteriaImpl.java:328)
at com.inversion.dal.BaseDAO.findUniqueByCriterion(BaseDAO.java:59)

Have I set something up wrong here?

Any help greatly appreciated.

Marty

+1  A: 

Turn off auto-flushing on the Session object to fix this exception.

Session s;
// if you're doing transactional work
s.setFlushMode(FlushMode.COMMIT);
// if you want to control flushes directly
s.setFlushMode(FlushMode.MANUAL);

This is not your error however. Something earlier in your code is causing the in memory objects to be in an invalid state which is trying to be persisted to the DB during the autoflush.

Jherico
I'm using annotations to mark transactional boundaries -- @Transactional(readOnly=false). I thought that this was the preferred way of handling boundaries rather than manually inside my code?Also, the entity is in an invalid state, but I'm not ready for it to be committed yet -- hibernate is doing that on it's own, during a SELECT. Why?
Marty Pitt
Just because you're in a transaction doesn't mean that SQL isn't going to be executed against the database. FlushMode controls when the SQL gets executed, not when the transaction gets committed. If you're going to be creating objects that have invalid state as far as your database is concerned, you may need to defer flushing until a later time in the way that Jherico suggests.
cliff.meyers
+2  A: 

hibernate remembers with objects needs to be saved. when issuing a select, hibernate will flush these changes. this ensures the select will return the correct results.

setting flushmode to anything else than FlushMode.AUTO will prevent this behaviour. But the error is in your code, where you pass an incomplete object to hibernate to persist or update. So the correct solution is to pass the object later to hibernate, when it is complete.

Salandur
While passing an incomplete object into hibernate is a good candidate for the null constraint violation, there are a lot of code paths that could trigger such an error, having to do with modification of items already in the session, so its not always obvious where the error is occuring.
Jherico