-->
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.  [ 3 posts ] 
Author Message
 Post subject: Cascade on OneToMany fails to assign primary key correctly.
PostPosted: Tue Jan 20, 2009 2:09 pm 
Newbie

Joined: Wed Oct 01, 2008 8:42 pm
Posts: 12
Issue Description
Basically, I have a simple one to many setup, with a quote object having several quote Items as it's children. When I save the quote, I want to have all quote items saved as well. The issue is that when I do this, the quote items do not get the correct quote set to them and hibernate tries to insert a null value instead. Not sure if my annotations are not configured correctly or something.

Hibernate version:
3.3.0.SP1
3.4.0.GA (annotations)

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

Classes

Code:
@Entity
@org.hibernate.annotations.GenericGenerator(name="increment", strategy="increment")
@Table(name="QUOTES")
public class Quote {
   @Id @GeneratedValue(generator="increment")
   @Column(name="QUOTE_ID", nullable=false)
   private Integer quoteId;
   
   @Column(name="QUOTE_NUMBER")
   private String quoteNumber;
   
   @ManyToOne(fetch=FetchType.LAZY)
   @JoinColumn(name="USER_ID")
   private LoginUser user;

   @Column(name="ISSUE_DATE")
   private Date issueDate;

   @Column(name="EXPIRATION_DATE")
   private Date expirationDate;
   
   @OneToMany(mappedBy="quote",  fetch=FetchType.LAZY, cascade=CascadeType.ALL)
   private Set<QuoteItem> quoteItems = new HashSet<QuoteItem>();
   
   public void addQuoteItem(QuoteItem item){
      this.quoteItems.add(item);
   }
   
   public void removeQuoteItem(QuoteItem item){
      this.quoteItems.remove(item);
   }
   
   /*
    * Getters and Setters
    */
   
   
   public Integer getQuoteId() {
      return quoteId;
   }

   public void setQuoteId(Integer quoteId) {
      this.quoteId = quoteId;
   }
   
   public String getQuoteNumber() {
      return quoteNumber;
   }

   public void setQuoteNumber(String quoteNumber) {
      this.quoteNumber = quoteNumber;
   }
   public LoginUser getUser() {
      return user;
   }
   public void setUser(LoginUser user) {
      this.user = user;
   }
   public Date getIssueDate() {
      return issueDate;
   }
   public void setIssueDate(Date issueDate) {
      this.issueDate = issueDate;
   }
   public Date getExpirationDate() {
      return expirationDate;
   }
   public void setExpirationDate(Date expirationDate) {
      this.expirationDate = expirationDate;
   }
   public Set<QuoteItem> getQuoteItems() {
      return quoteItems;
   }
   public void setQuoteItems(Set<QuoteItem> quoteItems) {
      this.quoteItems = quoteItems;
   }




Code:
@Entity
@org.hibernate.annotations.GenericGenerator(name="increment", strategy="increment")
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name="QUOTE_ITEMS")
public class QuoteItem {
   @Id @GeneratedValue(generator="increment")
   @Column(name="QUOTE_ITEM_ID")
   private Integer quoteItemId;
   
   @ManyToOne
   @JoinColumn(name="QUOTE_ID")
   private Quote quote;
   
   @Column(name="ITEM_COST")
   private BigDecimal itemCost;
   
   @Column(name="ITEM_OVERHEAD")
   private BigDecimal itemOverhead;
   
   @Column(name="QUANTITY")
   private BigDecimal quantity;
   
   @Column(name="TOTAL_COST")
   private BigDecimal totalCost;
   
   
   /*
    * Getters and setters
    */
   
   public Integer getQuoteItemId() {
      return quoteItemId;
   }
   public void setQuoteItemId(Integer quoteItemId) {
      this.quoteItemId = quoteItemId;
   }
   public Quote getQuote() {
      return quote;
   }
   public void setQuote(Quote quote) {
      this.quote = quote;
   }
   public BigDecimal getItemCost() {
      return itemCost;
   }
   public void setItemCost(BigDecimal itemCost) {
      this.itemCost = itemCost;
   }
   public BigDecimal getItemOverhead() {
      return itemOverhead;
   }
   public void setItemOverhead(BigDecimal itemOverhead) {
      this.itemOverhead = itemOverhead;
   }
   public BigDecimal getQuantity() {
      return quantity;
   }
   public void setQuantity(BigDecimal quantity) {
      this.quantity = quantity;
   }
   public BigDecimal getTotalCost() {
      return totalCost;
   }
   public void setTotalCost(BigDecimal totalCost) {
      this.totalCost = totalCost;
   }   
}


Test Case

Code:
   public void testCascading() throws Exception{
      Quote quote = new Quote();
      quote.setQuoteNumber("09BPF87654321");
      LoginUser user = loginUserDao.findByID(5255);
      quote.setUser(user);
      quote.setExpirationDate(new Date());
      quote.setIssueDate(new Date());
      
      QuoteItem item = new QuoteItem();
      item.setItemCost(new BigDecimal("1"));
      item.setItemOverhead(new BigDecimal("1"));
      item.setQuantity(new BigDecimal("1"));
      item.setTotalCost(new BigDecimal("1"));
      quote.addQuoteItem(item);
      quoteDao.save(quote);
      
      Quote assertQuote = quoteDao.findByID(quoteDao.getHighestID());
      Assert.assertEquals(new BigDecimal("1"), assertQuote.getQuoteItems().iterator().next().getItemCost());
   }


SQL Generated with Stack Trace

Code:
Hibernate: insert into QUOTE_ITEMS (ITEM_COST, ITEM_OVERHEAD, QUANTITY, QUOTE_ID, TOTAL_COST, QUOTE_ITEM_ID) values (?, ?, ?, ?, ?, ?)
Jan 20, 2009 1:03:55 PM org.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 1400, SQLState: 23000
Jan 20, 2009 1:03:55 PM org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: ORA-01400: cannot insert NULL into ("WWW"."QUOTE_ITEMS"."QUOTE_ID")

Jan 20, 2009 1:03:55 PM org.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 1400, SQLState: 23000
Jan 20, 2009 1:03:55 PM org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: ORA-01400: cannot insert NULL into ("WWW"."QUOTE_ITEMS"."QUOTE_ID")

Jan 20, 2009 1:03:55 PM org.hibernate.event.def.AbstractFlushingEventListener performExecutions
SEVERE: Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
   at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
   at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
   at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
   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:969)
   at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1114)
   at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
   at org.hibernate.impl.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:811)
   at edu.harvard.med.genome.database.GenericDaoHibernate.getHighestID(GenericDaoHibernate.java:75)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
   at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
   at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
   at $Proxy24.getHighestID(Unknown Source)
   at edu.harvard.med.genome.database.orders.quotes.test.TestQuote.testCascading(TestQuote.java:94)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.springframework.test.context.junit4.SpringTestMethod.invoke(SpringTestMethod.java:160)
   at org.springframework.test.context.junit4.SpringMethodRoadie.runTestMethod(SpringMethodRoadie.java:233)
   at org.springframework.test.context.junit4.SpringMethodRoadie$RunBeforesThenTestThenAfters.run(SpringMethodRoadie.java:333)
   at org.springframework.test.context.junit4.SpringMethodRoadie.runWithRepetitions(SpringMethodRoadie.java:217)
   at org.springframework.test.context.junit4.SpringMethodRoadie.runTest(SpringMethodRoadie.java:197)
   at org.springframework.test.context.junit4.SpringMethodRoadie.run(SpringMethodRoadie.java:143)
   at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:160)
   at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
   at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
   at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
   at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
   at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
   at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:97)
   at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.sql.BatchUpdateException: ORA-01400: cannot insert NULL into ("WWW"."QUOTE_ITEMS"."QUOTE_ID")

   at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
   at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10698)
   at org.apache.commons.dbcp.DelegatingPreparedStatement.executeBatch(DelegatingPreparedStatement.java:231)
   at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
   at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
   ... 44 more


Hack Fix

I'm able to work around this by changing the "addQuoteItem" method to be as follows:

Code:
   public void addQuoteItem(QuoteItem item){
      item.setQuote(this);
      this.quoteItems.add(item);
   }


However, I was under the impression that this should happen automatically in hibernate.

Thanks,
Tim


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 20, 2009 2:43 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Quote:
I'm able to work around this by changing the "addQuoteItem" method to be as follows:

public void addQuoteItem(QuoteItem item){
item.setQuote(this);
this.quoteItems.add(item);
}


However, I was under the impression that this should happen automatically in hibernate.


No it doesn't happen automatically and your "hack fix" is the proper way to do it. It is almost identical to the parent/child example in the Hibernate documentation: http://www.hibernate.org/hib_docs/v3/re ... bidir.html


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 20, 2009 3:29 pm 
Newbie

Joined: Wed Oct 01, 2008 8:42 pm
Posts: 12
Ah, interesting. For whatever reason I thought that this had happened behind the scenes in the past.

Thanks for the help!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 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.