-->
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: Bi-directional cascading failing possible bug?
PostPosted: Fri May 11, 2007 12:58 pm 
Regular
Regular

Joined: Fri Feb 13, 2004 10:02 pm
Posts: 90
The ManyToOne cascading does not appear to be working as I expect it to.
When I set the following cascade on a ManyToOne

@ManyToOne (cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH} )

I expect the saveOrUpdate call to cascade on all operations except delete if the "One" object (a CreditUnion object) is transient. When I set cascade type to ALL, the CreditUnion object is successfully saved with the cascade, otherwise I receive the TransientObject Exception Is this a bug?

I have included all of my files below for your review.
Object creation
Code:
//we Create a Credit Union and a ProcessInformation object to test
      //cascading
      CreditUnion cu = new CreditUnion();
      cu.setName("My Test CU");
      
      
      ProcessInformation info = new ProcessInformation();
      info.setNumberOfAccounts(new Long(20));
      
      info.setCreditUnion(cu);
      cu.addToProcessorRun(info);

                dao.saveOrUpdate(info);


Code to save
Code:
   /*
    * (non-Javadoc)
    *
    * @see com.purdueefcu.statements.dataaccess.IdentityDao#saveOrUpdate(com.purdueefcu.statements.dataaccess.bean.Identity)
    */
   public void saveOrUpdate(Identity identity) {
      if (identity == null) {
         throw new NullPointerException("identity cannot be null");
      }

      this.getHibernateTemplate().saveOrUpdate(identity);
   }


Hibernate version:
hibernate 3.3.0, annotations 3.3.0

Mapping documents:
Identity
Code:
@MappedSuperclass
//TODO TN, can we do table per subclass?
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Identity {

   /**
    * The id to map to the identity column of the table No setter is used to
    * avoid programmer error. Only the database should set the id.
    *
    * @uml.property name="id"
    */
   private Long id = null;

   /**
    * Getter of the property <tt>id</tt>
    *
    * @return Returns the id.
    * @uml.property name="id"
    */
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   // override and use direct field access to avoid creating a setter since
   // only hibernate should set the id from the id generated by the db
   @AccessType("field")
   public Long getId() {
      return id;
   }

   /*
    * (non-Javadoc)
    *
    * @see java.lang.Object#hashCode()
    */
   @Override
   public int hashCode() {
      final int PRIME = 31;
      int result = 1;
      result = PRIME * result + ((id == null) ? 0 : id.hashCode());
      return result;
   }

   /*
    * (non-Javadoc)
    *
    * @see java.lang.Object#equals(java.lang.Object)
    */
   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      final Identity other = (Identity) obj;
      if (id == null) {
         if (other.id != null)
            return false;
      } else if (!id.equals(other.id))
         return false;
      return true;
   }


Auditable
Code:
@MappedSuperclass
public abstract class Auditable extends Identity {

   /**
    * The date this object was created
    *
    * @uml.property name="createDate"
    */
   private Date createDate;

   /**
    * The update timestamp
    *
    * @uml.property name="updateDate"
    */
   private Date updateDate;
   
   public Auditable() {
      super();
   }

   

   /**
    * Getter of the property <tt>createDate</tt>
    *
    * @return Returns the createDate.
    * @uml.property name="createDate"
    */
   @Basic
   public Date getCreateDate() {
      return createDate;
   }

   /**
    * Setter of the property <tt>createDate</tt>
    *
    * @param createDate
    *            The createDate to set.
    * @uml.property name="createDate"
    */
   public void setCreateDate(Date createDate) {
      this.createDate = createDate;
   }

   /**
    * Getter of the property <tt>updateDate</tt>
    *
    * @return Returns the updateDate.
    * @uml.property name="updateDate"
    */
   @Basic
   public Date getUpdateDate() {
      return updateDate;
   }

   /**
    * Setter of the property <tt>updateDate</tt>
    *
    * @param updateDate
    *            The updateDate to set.
    * @uml.property name="updateDate"
    */
   public void setUpdateDate(Date updateDate) {
      this.updateDate = updateDate;
   }


CreditUnion
Code:
@Entity
public class CreditUnion extends Auditable {

   /**
    * @uml.property name="name2"
    */
   
   private String name;

   private List<ProcessInformation> processorRuns;

   /**
    *
    */
   public CreditUnion() {
      super();
   }

   /**
    * @return the name
    * @uml.property name="name"
    */
   @Basic
   public String getName() {
      return name;
   }

   /**
    * @param name
    *            the name to set
    * @uml.property name="name"
    */
   public void setName(String name) {
      this.name = name;
   }

   /**
    * @return the processorRuns
    */
   //links save/update/delete to all accounts.  The pointer to our current object in
   //the ProcessInformation object is the processInformation property
   @OneToMany(mappedBy="creditUnion", cascade = {CascadeType.ALL})
   public List<ProcessInformation> getProcessorRuns() {
      return processorRuns;
   }

   /**
    * @param processorRuns
    *            the processorRuns to set
    */
   public void setProcessorRuns(List<ProcessInformation> processorRuns) {
      this.processorRuns = processorRuns;
   }

   /**
    * Add the run to the list of runs
    *
    * @param run
    */
   public void addToProcessorRun(ProcessInformation run) {
      if (this.processorRuns == null) {
         this.processorRuns = new ArrayList<ProcessInformation>();
      }

      this.processorRuns.add(run);
   }

}


ProcessInformation
Code:
@Entity
public class ProcessInformation extends Auditable {

   private CreditUnion creditUnion;
   
   //number of accounts queued in the run
   private Long numberOfAccounts;
   
   private List<Account> accounts;
   
   /**
    *
    */
   public ProcessInformation() {
      super();
   }

   /**
    * @return the creditUnion
    */
   @ManyToOne (cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH} )
   public CreditUnion getCreditUnion() {
      return creditUnion;
   }

   /**
    * @param creditUnion the creditUnion to set
    */
   public void setCreditUnion(CreditUnion creditUnion) {
      this.creditUnion = creditUnion;
   }

   /**
    * @return the numberOfAccounts
    */
   @Basic
   public Long getNumberOfAccounts() {
      return numberOfAccounts;
   }

   /**
    * @param numberOfAccounts the numberOfAccounts to set
    */
   public void setNumberOfAccounts(Long numberOfAccounts) {
      this.numberOfAccounts = numberOfAccounts;
   }

   /**
    * @return the accounts
    */
   //links save/update/delete to all accounts.  The pointer to our current object in
   //the Account object is the processInformation property
   @OneToMany (mappedBy="processInformation", cascade = {CascadeType.ALL})
   public List<Account> getAccounts() {
      return accounts;
   }

   /**
    * @param accounts the accounts to set
    */
   public void setAccounts(List<Account> accounts) {
      this.accounts = accounts;
   }

   /**
    * Add the account to the list
    * @param acct
    */
   public void addAccount(Account acct){
      if(accounts == null){
         this.accounts = new ArrayList<Account>();
      }
      
      this.accounts.add(acct);
   }
}

Name and version of the database you are using:
MySQL 5.0 InnoDB Dialect


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 14, 2007 12:29 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
it would be if you were using Hibernate Entity Manager
But since you are using HAN + Hibernate Core, the Hibernate semantic applied,
adding @Cascade(CascadeType.SAVE_UPDATE) will do the trick

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 14, 2007 4:18 pm 
Regular
Regular

Joined: Fri Feb 13, 2004 10:02 pm
Posts: 90
Gotcha. Thanks for the information. It was initially confusing to me to use the javax.persistance packages for the Entity tags as well as mapping, but use the Hibernate tags for cascading. Thanks for the information.

Todd


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.