Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: Integration test against a ConstraintViolationException
PostPosted: Sat Jul 31, 2010 3:59 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
I get a org.hibernate.exception.ConstraintViolationException in an integration test.

I have two tables, one is contact_referer and another one is contact.

The contact has an external key pointing to the primary key of contact_referer.

If a contact_referer is being used by a contact then the contact_referer should not be deletable.

And indeed it is not deletable.

I would like to check for this correct behavior in an integration test.

And so I came up with the following test:
Code:
   @Test
   public void testDelete() {
      contactReferer0 = contactRefererDao.saveOrUpdate(contactReferer0);
      contactReferer1 = contactRefererDao.saveOrUpdate(contactReferer1);
      long count = contactRefererDao.countAllRows();
      assertEquals(2, count);
      contactRefererDao.delete(contactReferer0);
      count = contactRefererDao.countAllRows();
      assertEquals(1, count);
      contact = new Contact();
      contact.setEmail("email");
      contact.setMessage("message");
      DateTime contactDateTime = new DateTime();
      contact.setContactDateTime(contactDateTime);
      contact.setContactReferer(contactReferer1);
      contact = contactDao.saveOrUpdate(contact);
      try {
         contactRefererDao.delete(contactReferer1);
         fail(); // line 69
      } catch (ConstraintViolationException e) {
      }
      count = contactRefererDao.countAllRows(); // line 72
      assertEquals(1, count);
      contact.setContactReferer(null);
      contactRefererDao.delete(contactReferer1);
      count = contactRefererDao.countAllRows();
      assertEquals(0, count);
   }


But the fail() is executed as the test gives the following exception:
Code:
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 7.694 sec <<< FAILURE!
testDelete(com.thalasoft.learnintouch.core.dao.ContactRefererDaoTest)  Time elapsed: 0.189 sec  <<< FAILURE!
java.lang.AssertionError:
        at org.junit.Assert.fail(Assert.java:74)
        at org.junit.Assert.fail(Assert.java:81)
        at com.thalasoft.learnintouch.core.dao.ContactRefererDaoTest.testDelete(ContactRefererDaoTest.java:69)


with the line 69 being the line:
Code:
         fail();


You can also see some comments in the code with the line numbers.

And so, I commented out the fail() statement, and got the following exception:
Quote:
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 7.581 sec <<< FAILURE!
testDelete(com.thalasoft.learnintouch.core.dao.ContactRefererDaoTest) Time elapsed: 0.215 sec <<< ERROR!
org.hibernate.exception.ConstraintViolationException: could not delete: [com.thalasoft.learnintouch.core.domain.ContactReferer#203]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2536)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2692)
at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:77)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:172)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:41)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:970)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1563)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at com.thalasoft.learnintouch.core.dao.hibernate.GenericHibernateDao.countAllRows(GenericHibernateDao.java:88)
at com.thalasoft.learnintouch.core.dao.ContactRefererDaoTest.testDelete(ContactRefererDaoTest.java:72)


As you can see, it seems like the statement
Code:
count = contactRefererDao.countAllRows();

right after the try catch block, triggers the delete.

So I tried to trigger the delete sooner, that is, in the try block, with a flush() statement as in
Code:
      try {
         contactRefererDao.delete(contactReferer1);
         contactRefererDao.getSession().flush();
         fail();
      } catch (ConstraintViolationException e) {
      }


But it still gives me the same exception:
Quote:
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 7.476 sec <<< FAILURE!
testDelete(com.thalasoft.learnintouch.core.dao.ContactRefererDaoTest) Time elapsed: 0.246 sec <<< ERROR!
org.hibernate.exception.ConstraintViolationException: could not delete: [com.thalasoft.learnintouch.core.domain.ContactReferer#205]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2536)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2692)
at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:77)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:172)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:41)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:970)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1563)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at com.thalasoft.learnintouch.core.dao.hibernate.GenericHibernateDao.countAllRows(GenericHibernateDao.java:88)
at com.thalasoft.learnintouch.core.dao.ContactRefererDaoTest.testDelete(ContactRefererDaoTest.java:73)


with the line 73 still being the line:
Code:
      count = contactRefererDao.countAllRows();


And so, I decided to have that line in the try block, right after the delete, to see if it would trigger the delete, as the flush seemed not to do it, and had a test that looked like:
Code:
   @Test
   public void testDelete() {
      contactReferer0 = contactRefererDao.saveOrUpdate(contactReferer0);
      contactReferer1 = contactRefererDao.saveOrUpdate(contactReferer1);
      long count = contactRefererDao.countAllRows();
      assertEquals(2, count);
      contactRefererDao.delete(contactReferer0);
      count = contactRefererDao.countAllRows();
      assertEquals(1, count);
      contact = new Contact();
      contact.setEmail("email");
      contact.setMessage("message");
      DateTime contactDateTime = new DateTime();
      contact.setContactDateTime(contactDateTime);
      contact.setContactReferer(contactReferer1);
      contact = contactDao.saveOrUpdate(contact);
      try {
         contactRefererDao.delete(contactReferer1);
         count = contactRefererDao.countAllRows();
         fail();
      } catch (ConstraintViolationException e) {
      }
      count = contactRefererDao.countAllRows();
      assertEquals(1, count);
      contact.setContactReferer(null);
      contactRefererDao.delete(contactReferer1);
      count = contactRefererDao.countAllRows();
      assertEquals(0, count);
   }


But it still gives me the exception:
Quote:
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 7.674 sec <<< FAILURE!
testDelete(com.thalasoft.learnintouch.core.dao.ContactRefererDaoTest) Time elapsed: 0.21 sec <<< ERROR!
org.hibernate.exception.ConstraintViolationException: could not delete: [com.thalasoft.learnintouch.core.domain.ContactReferer#207]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2536)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2692)
at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:77)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:172)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:41)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:970)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1563)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at com.thalasoft.learnintouch.core.dao.hibernate.GenericHibernateDao.countAllRows(GenericHibernateDao.java:88)
at com.thalasoft.learnintouch.core.dao.ContactRefererDaoTest.testDelete(ContactRefererDaoTest.java:73)


Why is it that the exception does not show the line 69, the one containing the statement
Code:
count = contactRefererDao.countAllRows();

in the try block, instead of the same statement after the catch block ?

I guess there is something that escapes me here..

Any clue ?


Top
 Profile  
 
 Post subject: Re: Integration test against a ConstraintViolationException
PostPosted: Sat Jul 31, 2010 4:26 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
You need to read a bit about exception handling in Hibernate (http://docs.jboss.org/hibernate/stable/ ... exceptions). In your last test code I believe that the ConstraintViolationException is actually thrown inside the try block. But since an exception has happened you should not continue using the same session. In this case, the second call to contactRefererDao.countAllRows() triggers the delete statement to be executed again. But note that Hibernate makes no guarantee what will happen to a session after an exception has occurred. What you should do inside the catch block is to rollback and close the current session, start a new session and make sure that the objects that you manipulate later in the code are attached to the new session.


Top
 Profile  
 
 Post subject: Re: Integration test against a ConstraintViolationException
PostPosted: Sat Jul 31, 2010 4:35 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
Hej Nordborg !

You have more guidance on how to go about doing this:

"What you should do inside the catch block is to rollback and close the current session, start a new session and make sure that the objects that you manipulate later in the code are attached to the new session."

Tack !


Top
 Profile  
 
 Post subject: Re: Integration test against a ConstraintViolationException
PostPosted: Sat Jul 31, 2010 4:51 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
I just read this article

http://www.javaworld.com/cgi-bin/mailto ... te=jw_core

I leads me to think that I should handle the Hibernate unchecked exceptions in the Dao layer, and throw some business friendly exceptions to the client gui code, so as to have friendlier messages sent to the users up there.

Should I try to have in my Dao layer a catching of all Hibernate unchecked exceptions into some business-like checked exception ? Like, for example, have a following exception:
Code:
   public class DaoException extends HibernateException {
      private Exception hiddenException;

      public DaoException(String error, Exception exception) {
         super(error);
         hiddenException = exception;
      }

      public Exception getHiddenException() {
         return (hiddenException);
      }
   }


And use it in the Dao layer like:
Code:
   public void insertContact(Contact contact) throws DaoException {
      try {
         contactDao.saveOrUpdate(contact);
      } catch (SQLException sqlException) {
         // do something
         throw new DaoException("Insert of contact failed", sqlException);
      }
   }


Do you let all Hibernate unchecked exceptions bubble up out of your Dao ?

Or do you catch them and throw business friendlier ones ?


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

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.