-->
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: Merge Bug? or Impossible to Recover from Database Exception?
PostPosted: Fri Nov 06, 2009 1:54 pm 
Newbie

Joined: Wed Jul 19, 2006 9:46 am
Posts: 5
In the following a "run down" of the Testcase, which reproduces a problem we ran into with EntityManager.merge after an Database Exception.

We have a Entity A has a Jpa OneToMany Relationship to Entity B The OneToMany Relationship has CasadeType.ALL

In the database addtionally to the mapped Tables and Foreign Key, a Insert Trigger on Entity B, which always raises an Exception.

Here the Testcase szenario, see also the code below:

1. Create new Entity Manager
2. Begin Transaction
3. Read Entity A from Database
4. Create a B and Set a Text
5. Add it to A
6. Persist A
7. Catch exptected Exception because of Trigger on Insert of B, which always raises a exception
8 In the Catch Block: Close Entity Manager (just in Case)
9. Create a New Entity Manager
10. Merge A with Casade All Option
11. Remove B from A,
12. Assert Size of Bs of A to be 0
13. Persist A
14. Unexpected Exception : The Exception is the same as in 7. See attached Exception Stack:
Hibernate generates a Insert of a B

A Bug? Potentially this has tremendous impact on our application, since we have many "Business Rules" in the Database: the Application has to be able to Recover from these Exceptions.

Or - also very possible - i am missing something completely .... the szenario, which i would welcome most ;-))

We are using Spring: 2.5.4 with Hibernate 3.2.6.ga with Jpa and Oracle 10g

My persistent classes:

Code:
@Entity
@Table(name = "A")
public class A {

   @Id
   @javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.SEQUENCE, generator = "aIdSeq")
   @javax.persistence.SequenceGenerator(name = "aIdSeq", sequenceName = "A_SEQ", allocationSize = 1)
   @javax.persistence.Column(name = "AID", nullable = false)
   private Long id;

   @javax.persistence.OneToMany(mappedBy = "a", cascade=CascadeType.ALL)
   private List<B> bs = new ArrayList<B>();

   public List<B> getBs() {
      return bs;
   }

   public void setBs(List<B> bs) {
      this.bs = bs;
   }

   public B addB(final B b) {
      getBs().add(b);
      b.setA(this);
      return b;
   }
   
   public B removeB(final B b) {
      getBs().remove(b);
      return b;
   }

   public Long getId() {
      return id;
   }
}


Code:
@Entity
@Table(name = "B")
public class B {

   @SuppressWarnings("unused")
   @Id
   @javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.SEQUENCE, generator = "bIdSeq")
   @javax.persistence.SequenceGenerator(name = "bIdSeq", sequenceName = "B_SEQ", allocationSize = 1)
   @javax.persistence.Column(name = "BID", nullable = false)
   private Long id;

   @javax.persistence.Column(name = "TEXT", nullable = false)
   private String text;

   @ManyToOne(fetch = javax.persistence.FetchType.LAZY, optional = false)
   @JoinColumn(name = "AID",nullable = false)
   private A a;

   public A getA() {
      return a;
   }

   public void setA(A a) {
      this.a = a;
   }

   public String getText() {
      return text;
   }

   public void setText(String text) {
      this.text = text;
   }

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

}


Note : On Table B there is a Insert Trigger which always raises an Exception

And here my Testcase:
Code:
      @Test
   public void testInsertWithFlushAndExceptionAndRecovery() throws Exception {
      EntityManager entityManager = entityManagerFactory.createEntityManager();
      EntityTransaction transaction = entityManager.getTransaction();
      transaction.begin();
      A a = entityManager.find(A.class, 1L);
      B b = new B();
      b.setText("Some Test");
      a.addB(b);
      entityManager.persist(a);
      try {
         entityManager.flush();
      }
      catch (Exception e) {
         // Exception is "ok" , because of Database Trigger on Insert of B
         entityManager.close(); // Just in case
         entityManager = entityManagerFactory.createEntityManager();
         transaction = entityManager.getTransaction();
         transaction.begin();
         A mergedA = entityManager.merge(a);
         mergedA.removeB(b);
         Assert.assertTrue(mergedA.getBs().size() == 0);
         entityManager.persist(mergedA);
         try {
            entityManager.flush();
            // No Exception Expected
         }
         catch (Exception ex) {
            Assert.fail("We get the same Exception with insert of b, although we remove b from a");
         }
         transaction.rollback();
         entityManager.close();
      }

   }


Here the Exception, which is the same in both cases:
Code:
Hibernate: select a0_.AID as AID0_1_, bs1_.AID as AID3_, bs1_.BID as BID3_, bs1_.BID as BID1_0_, bs1_.AID as AID1_0_, bs1_.TEXT as TEXT1_0_ from A a0_ left outer join B bs1_ on a0_.AID=bs1_.AID where a0_.AID=?
Hibernate: select b0_.BID as BID1_0_, b0_.AID as AID1_0_, b0_.TEXT as TEXT1_0_ from B b0_ where b0_.BID=?
Hibernate: select B_SEQ.nextval from dual
Hibernate: insert into B (AID, TEXT, BID) values (?, ?, ?)
2009-11-09 13:27:57,425 WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 20499, SQLState: 72000
2009-11-09 13:27:57,425 ERROR org.hibernate.util.JDBCExceptionReporter - ORA-20499: GP-10074: Kontonummer  ist nicht korrekt (Prüfziffer).
ORA-06512: at "AENV.EXCEPTION_PA", line 16
ORA-06512: at "VK.TRG_EXC", line 4
ORA-04088: error during execution of trigger 'VK.TRG_EXC'

2009-11-09 13:27:57,425 WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 20499, SQLState: 72000
2009-11-09 13:27:57,425 ERROR org.hibernate.util.JDBCExceptionReporter - ORA-20499: GP-10074: Kontonummer  ist nicht korrekt (Prüfziffer).
ORA-06512: at "AENV.EXCEPTION_PA", line 16
ORA-06512: at "VK.TRG_EXC", line 4
ORA-04088: error during execution of trigger 'VK.TRG_EXC'

2009-11-09 13:27:57,425 ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session


I would'nt expect to get the second Exception upon the persist of A, since the first transaction has been rolled back and the instance of B is removed from A after the merge.


Any hints, input greatly appreciated
Christoph


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.