14 Replies Latest reply on Jun 14, 2006 4:18 AM by Hoagie X

    uniqueconstraint in ejb3.0

    Ruud van Kersbergen Newbie

      @Entity
      @Table(name = "protodevice", uniqueConstraints={@UniqueConstraint(columnNames={"name"})})
      public class Device {
      private int id;
      private String name;

      @Id(generate = GeneratorType.AUTO)
      public int getId () { return id;}
      public void setId(int id) {this.id = id;}

      public String getName() {return name; }
      public void setName(String name) {this.name = name;}

      }

      I try to insert a object this way :

      adddevice (Device dev)

      Device dbDev = em.find(Device.class,dev.getId() );
      em.merge(dev);

      If i insert a object that violates the constraint then the following happens:
      - stacktrace on the console :
      2005-10-04 11:11:39,234 WARN [org.hibernate.util.JDBCExceptionReporter] SQL Error: 1062, SQLState: 23000
      2005-10-04 11:11:39,234 ERROR [org.hibernate.util.JDBCExceptionReporter] Duplicate key or integrity constraint violation message from server: "Duplicate entry 'Bestaat' for key 2"
      2005-10-04 11:11:39,281 ERROR [org.hibernate.event.def.AbstractFlushingEventListener] Could not synchronize database state with session
      org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
      at org.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:74)
      at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)

      - and the calling methode receives a java.lang.Exception.

      If change the code to :
      adddevice (Device dev)

      Device dbDev = em.find(Device.class,dev.getId() );
      try {
      em.merge(dev);
      em.flush();
      } catch (org.hibernate.exception.ConstraintViolationException ex) {
      ....
      }
      then the exception is catched BUT the stacktrace is still on the console.

      The same thing happens if i remove the uniqueconstraint on the table and put it on the column :

      @Column(name="name", unique=true)
      public String getName() {
      return name;
      }

      What is the best solution to nicely catch the exception and to eliminate the stacktrace ???

        • 1. Re: uniqueconstraint in ejb3.0
          L.A. D.Z. Newbie

          I've a similar problem... In my example i try to add a row in a table using manager.persist(obj) (where obj is mapped to a table) that violate a unique constraint, and i get the same WARN and ERROR on the server console. I've tried to try/catch the manager.persist(obj) but Exception is not catched... and the remote caller catch Exception but not ConstraintViolationException, and it reports "org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=intel650/201, BranchQual=, localId=201] status=STATUS_NO_TRANSACTION; - nested throwable: (org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update)".
          How to catch this kind of exception? I want to elimate the stacktrace in the server and I'd like to catch this sort of exception because I need to be informed of the error type.
          Thanks!

          • 2. Re: uniqueconstraint in ejb3.0
            David Webster Newbie

            Me, too. Have yet to figure it out. Can't even find any attempt to handle basic errors in the JBoss Trailblazers...

            • 3. Re: uniqueconstraint in ejb3.0
              Jason Cunningham Newbie

              Did anybody have any luck with this?

              • 4. Re: uniqueconstraint in ejb3.0
                Cyril JOUI Newbie

                Hello,

                Did you try to add :

                @Column(unique=true)
                


                ?



                • 5. Re: uniqueconstraint in ejb3.0
                  Jason Cunningham Newbie

                  Hi,

                  The problem isn't that the constraint isn't being applied - it is, and it's working fine. The problem is that we can't catch the exception gracefully.

                  For example:
                  1) Create a user named 'bob'
                  2) Create another user also called 'bob'

                  This generates an exception - which is fine. The 'Caused by' will be java.sql.SQLException: Duplicate entry 'bob' for key 2. I can catch the Exception in the Stateless Session Bean which is creating the user Entity Beans (org.hibernate.exception.ConstraintViolationException), but this doesn't stop the bubble of the Exception. I next get the following in my log:

                  ERROR [AssertionFailure] an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)

                  For example, If a Stateless Session Bean looks like this:

                  
                  public boolean addUser(String username) {
                   try {
                   User newUser = new User(username);
                   em.persist(newUser);
                   return true;
                   } catch (Exception e) {
                   /* Ignore exception */
                   return false;
                   }
                  }
                  


                  i would expect the method to return false in the event of a duplicate key insert...and that be the end of it. But, what actually happens is a the AssertionFailure exception.

                  My guess is this is something to do with the underlying Hibernate session.

                  What I'd like to do is stop the AssertionFailure exception from occuring.

                  Any help or ideas would be appreciated

                  Thanks,

                  Jason

                  • 6. Re: uniqueconstraint in ejb3.0
                    Francesco Persico Newbie

                    same problem here! noone can solve this? i hope in a eary answer tnx ;)

                    • 7. Re: uniqueconstraint in ejb3.0
                      jonefun Newbie

                      To catch a constraint violation in your session bean you need to call flush() on the entity manager.

                      See this thread for more information :

                      http://www.jboss.com/index.html?module=bb&op=viewtopic&t=71611

                      Cheers

                      Jono

                      • 8. Re: uniqueconstraint in ejb3.0
                        Jason Cunningham Newbie

                        Hi,

                        I tried your suggestion, but I get exactly the same problem. Here's my new code:

                        public boolean addUser(String username) {
                         try {
                         User newUser = new User(username);
                         em.persist(newUser);
                         em.flush();
                        
                         return true;
                         } catch (Exception e) {
                         /* Ignore exception */
                         return false;
                         }
                        }

                        Reading the other thread that you pointed us at, it seems that the only way to get around this is to catch the exception in the calling code. From what I can gather, the best way to do this is to create a new Exception class and annotate it with '@ApplicationException(rollback=true)'.

                        My problem remains though, the exception cannot be handled and quashed within the Session bean's 'addUser' method...is my understanding correct?

                        Thanks for your help,

                        Jason

                        • 9. Re: uniqueconstraint in ejb3.0
                          jonefun Newbie

                          As long as the column has the unique constraint annotated and you call flush() on the entity manager that should be all you need to force the exception in your session bean class.

                          • 10. Re: uniqueconstraint in ejb3.0
                            Jason Cunningham Newbie

                            Thanks for your reply.

                            My entity does have the relevent field annotated as unique

                            @Column(nullable=false, unique=true)
                            public String getUsername() {
                             return username;
                            }
                            
                            public void setUsername(String username) {
                             this.username = username;
                            }
                            


                            and I have a em.flush() in my session bean. As I mentioned before, the Exception is caught by my session bean.
                            org.hibernate.exception.ConstraintViolationException


                            but then I get:
                            16:37:20,640 ERROR [AssertionFailure] an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
                            org.hibernate.AssertionFailure: null id in com.sega.kongo.entity.user.KongoUser entry (don't flush the Session after an exception occurs)

                            This makes some sense to me...because the creation of the User failed, the 'id' will indeed be null. I tried to rollback the transaction (in the 'catch' block of my session bean

                            em.getTransaction().rollback();


                            but that failed miserably with the following exception message: Illegal to call this method from injected, managed EntityManager

                            Just to make sure that this isn't a potential bug in JBoss, with which version of JBoss have you successfully applied this strategy? I'm using jboss-4.0.3SP1.

                            Thanks as always,

                            Jason

                            • 11. Re: uniqueconstraint in ejb3.0
                              Ruud van Kersbergen Newbie

                              Hi,

                              I started this thread but unfortunatly the solution is still not presented.
                              Can somebody rewrite the initial example and eliminate the exception : org.hibernate.exception.ConstraintViolationException

                              because i want to catch a java/j2ee defined exception to make it possible to run my ear-file within every application-server.

                              • 12. Re: uniqueconstraint in ejb3.0
                                Jason Cunningham Newbie

                                I've done some reading, and I think it's working properly...

                                http://docs.jboss.org/ejb3/app-server/HibernateEntityManager/reference/en/html_single/index.html

                                Section 4.2.3. Exception handling

                                If the EntityManager throws an exception (including any SQLException), you should immediately rollback the database transaction, call EntityManager.close() (if createEntityManager() has been called) and discard the EntityManager instance. Certain methods of EntityManager will not leave the persistence context in a consistent state. No exception thrown by an entity manager can be treated as recoverable. Ensure that the EntityManager will be closed by calling close() in a finally block. Note that a container managed entity manager will do that for you. You just have to let the RuntimeException propagate up to the container.


                                So it would seem that catching the exception in the calling code is the only way to go. Following this approach, then the link that Jono provided gives all the information you need, namely 1) calling em.flush and 2) creating and annotating a checked excpetion (with @ApplicationException)
                                http://www.jboss.com/index.html?module=bb&op=viewtopic&t=71611


                                Cheers,

                                Jason

                                • 13. Re: uniqueconstraint in ejb3.0
                                  Ruud van Kersbergen Newbie

                                  It works that way, but as you can see in the example at the beginning of this thread (the flush and @ApplactionException) are already in place.

                                  My problem stays : the class org.hibernate.exception.ConstraintViolationException is imported in the bean and this makes it impossible to use the bean in an ear on another application server !

                                  Correct me if i am wrong.

                                  Greetings
                                  Ruud van Kersbergen

                                  • 14. Re: uniqueconstraint in ejb3.0
                                    Hoagie X Newbie

                                    Thta won't work. This problem has been around since the birthdays of Hibernate.

                                    Basically it comes down to this:

                                    The exception that is throw isn't thrown back through the call-chain, but rather through the container. This exception doesn't 'land' back in your application until it reaches the starting point of the transaction, which must commonly is your Session Facade.

                                    To this day, I haven't found a fix for this problem, but I will keep trying.


                                    ps. Even if calling flush() were to fix the problem, it still wouldn't be the solution, since you are flushing your entire EntityManager, which can cause a problem that wasn't created in the current unique-contraint situation, but it would be caught there, giving you the false impression that a unique contraint was violated.