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.  [ 23 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: One-To-One mapping, cascade delete issue
PostPosted: Thu Aug 14, 2008 1:00 pm 
Newbie

Joined: Wed Aug 13, 2008 10:30 am
Posts: 11
Hello Hibernate Gurus

I have two classes (Purchase & PendingPayment) mapped with One-To-One bi-directional relationship. A Purchase may or may not have a pending payment but a purchase must exists for a pendingPayment. The classes share the primary key.

When I add the pendingPayment object to my Purchase and save it, an appropriate record is created in the pendingPayment table, but when I remove this reference and save/merge the purchase object, the record is not removed from the pendingPayment table. I have tried setting the cascade to CascadeType.ALL and CascadeType.DELETE_ORPHAN, but the delete on the child table just does not seem to be happening.

Any help on what I might be doing wrong would be greatly appreciated!

Following is simplified version of my code:

Purchase
Code:
package test;

import javax.persistence.*;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

@Entity
@Table(name = "PURCHASE")
public class Purchase {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "PURCHASE_ID")
    private Long id;

    @OneToOne(optional = true, fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
@org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.DELETE_ORPHAN,
        org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    @PrimaryKeyJoinColumn
    private PendingPayment pendingPayment;

    public Long getId() {
        return id;
    }

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

    Purchase() {
    }

    public void addPending() {
        if (pendingPayment == null) {
            pendingPayment = new PendingPayment(this);
            pendingPayment.setPaymentStatus("NEW");
        }
    }
   
    public void removePending() {
        if (pendingPayment != null) {
            pendingPayment.setPurchase(null);
            pendingPayment = null;
        }
    }
}


PendingPayment
Code:
package test;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

@Entity
@Table(name="PENDING_PAYMENT")
public class PendingPayment {

    @Id @GeneratedValue (generator="hibernate_foreign")
    @GenericGenerator(name = "hibernate_foreign", strategy = "foreign", parameters = {
            @Parameter(name="property", value="purchase")})
    @Column(name = "PURCHASE_ID")
    Long id;
   
    @OneToOne(mappedBy = "pendingPayment", optional = false)
    Purchase purchase;
   
    @Column(name = "PAYMENT_STATUS")
    String paymentStatus;
   
    PendingPayment(Purchase purchase) {
        setPurchase(purchase);
    }
   
    public Long getId() {
        return id;
    }
   
    public void setId(Long id) {
        this.id = id;
    }
   
    public Purchase getPurchase() {
        return purchase;
    }
   
    public void setPurchase(Purchase purchase) {
        this.purchase = purchase;
    }
   
    public String getPaymentStatus() {
        return paymentStatus;
    }
   
    public void setPaymentStatus(String paymentStatus) {
        this.paymentStatus = paymentStatus;
    }
}


Here is the code that drives the operation

Code:
      Session session = HibernateUtil.getSessionFactory().openSession();
      Transaction tx = session.beginTransaction();
      
      Purchase purchase = new Purchase();      
      purchase.addPending();
      session.save(purchase);
      
      tx.commit();
      
      Transaction newTransaction = session.beginTransaction();
      
      purchase.removePending();
      session.merge(purchase);
      newTransaction.commit();
      
      session.close();


Following is my configuration of the session factory

Code:
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql:///test</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">testdb</property>
        <property name="hibernate.default_schema">test</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
   <property name="hibernate.hbm2ddl.auto">update</property>
   <property name="show_sql">true</property>
   <property name="format_sql">true</property>
      
   <mapping class="test.Purchase" />
   <mapping class="test.PendingPayment" />
    </session-factory>


Hibernate version:
Hibernate Core: 3.2.6
Hibernate Annotations: 3.3.1

Name and version of the database you are using:
MySQL version 4.1.20

Thank You.


Top
 Profile  
 
 Post subject: One to One delete
PostPosted: Thu Aug 14, 2008 2:24 pm 
Beginner
Beginner

Joined: Thu Jan 13, 2005 10:50 am
Posts: 30
Location: Minneapolis, MN
Can you try making constrained=true in the one-to-one mapping

Also if you can post the code where you remove the reference and save then it would be great

_________________
** Rate me if the solution was useful **

Regards,
Paras Jain


Top
 Profile  
 
 Post subject: Also try this
PostPosted: Thu Aug 14, 2008 2:34 pm 
Beginner
Beginner

Joined: Thu Jan 13, 2005 10:50 am
Posts: 30
Location: Minneapolis, MN
On the second thought,
also try to remove the following line
pendingPayment.setPurchase(null);

Add getters and setters for pending payment and just keep the following line

where you try to remove the pending payment
public void removePending() {
if (pendingPayment != null) {
// pendingPayment.setPurchase(null);
setPendingPayment(null);
}
}

//Getters and setters for pending payment

_________________
** Rate me if the solution was useful **

Regards,
Paras Jain


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 14, 2008 2:37 pm 
Newbie

Joined: Wed Aug 13, 2008 10:30 am
Posts: 11
Thank you for the quick response. I could not find an annotation for setting contrained attribute. Do you know a way to set that using Annotations? If not, then I will try to do the mapping in XML and setting this attribute to see if that makes a difference.

The code that removes the reference is the removePending method in Purchase object. I'm listing it here again.

Code:
    public void removePending() {
        if (pendingPayment != null) {
            pendingPayment.setPurchase(null);
            pendingPayment = null;
        }


This method is invoked by the driver as listed in the drive above. The specific code is

Code:
      purchase.removePending();
      session.merge(purchase);
      newTransaction.commit();


Thank You.


Top
 Profile  
 
 Post subject: Re: Also try this
PostPosted: Thu Aug 14, 2008 2:42 pm 
Newbie

Joined: Wed Aug 13, 2008 10:30 am
Posts: 11
parasjain01 wrote:
On the second thought,
also try to remove the following line
pendingPayment.setPurchase(null);

Add getters and setters for pending payment and just keep the following line

where you try to remove the pending payment
public void removePending() {
if (pendingPayment != null) {
// pendingPayment.setPurchase(null);
setPendingPayment(null);
}
}

//Getters and setters for pending payment


Added the getters and setters as you recommended and removed the
Code:
pendingPayment.setPurchase(null);
but the deletes are still not bring generated.


Top
 Profile  
 
 Post subject: Cascade Style
PostPosted: Thu Aug 14, 2008 2:51 pm 
Beginner
Beginner

Joined: Thu Jan 13, 2005 10:50 am
Posts: 30
Location: Minneapolis, MN
Trying putting Cascade style as just Delete instead of Delete_Orphan

_________________
** Rate me if the solution was useful **

Regards,
Paras Jain


Top
 Profile  
 
 Post subject: Re: Cascade Style
PostPosted: Thu Aug 14, 2008 3:22 pm 
Newbie

Joined: Wed Aug 13, 2008 10:30 am
Posts: 11
parasjain01 wrote:
Trying putting Cascade style as just Delete instead of Delete_Orphan


I tried it but to no avail.
As I noted in my original post, I tried setting the cascade to ALL also, but that did not help either. I am currently in the process of doing the mapping in XML instead of using annotations. I will then try setting the constrained to true and report the result.

Thanks!


Top
 Profile  
 
 Post subject: Re: Cascade Style
PostPosted: Thu Aug 14, 2008 3:33 pm 
Newbie

Joined: Wed Aug 13, 2008 10:30 am
Posts: 11
parasjain01 wrote:
Trying putting Cascade style as just Delete instead of Delete_Orphan


I tried it but to no avail.
As I noted in my original post, I tried setting the cascade to ALL also, but that did not help either. I am currently in the process of doing the mapping in XML instead of using annotations. I will then try setting the constrained to true and report the result.

Thanks!


Top
 Profile  
 
 Post subject: merge vs save
PostPosted: Thu Aug 14, 2008 3:45 pm 
Beginner
Beginner

Joined: Thu Jan 13, 2005 10:50 am
Posts: 30
Location: Minneapolis, MN
Why are you doing merge. Why don't you try just saveOrUpdate.

Try this with annotations only.

_________________
** Rate me if the solution was useful **

Regards,
Paras Jain


Top
 Profile  
 
 Post subject: Re: merge vs save
PostPosted: Thu Aug 14, 2008 4:10 pm 
Newbie

Joined: Wed Aug 13, 2008 10:30 am
Posts: 11
parasjain01 wrote:
Why are you doing merge. Why don't you try just saveOrUpdate.

Try this with annotations only.


The merge is because the addition of pending payment and removal are in separate transactions and the purchase could have other modifications between the time when a pending payment is added and when it is removed. For this particular simplified example, I did try both save and saveOrUpdate, neither worked.

I also, separately, performed the mapping in XML and added the constrained=true attribute to the one-to-one mapping of pendingPurchase, but that did not help either. Following are the mappings.

Purchase.hbm.xml
Code:
<hibernate-mapping package="test">
   <class name="Purchase" table="PURCHASE">
      <id name="id" column="PURCHASE_ID">
         <generator class="increment" />
      </id>
      <one-to-one name="pendingPayment"
               class="PendingPayment"
               cascade="all" />               
   </class>
</hibernate-mapping>


PendingPayment.hbm.xml
Code:
<hibernate-mapping package="test">
   <class name="PendingPayment" table="PENDING_PAYMENT">
      <id name="id" column="PURCHASE_ID">
         <generator class="foreign">
            <param name="property">purchase</param>
         </generator>
      </id>

      <one-to-one name="purchase"
               class="Purchase"
               constrained="true" />
      <property name="paymentStatus" column="PAYMENT_STATUS" />
   </class>
</hibernate-mapping>


Any ideas? Anyone?
Thanks!


Top
 Profile  
 
 Post subject: Last try
PostPosted: Thu Aug 14, 2008 4:35 pm 
Beginner
Beginner

Joined: Thu Jan 13, 2005 10:50 am
Posts: 30
Location: Minneapolis, MN
Seems strange that saveOrUpdate also doesn't work

For this particular example try this(if this also doesn't work then I am out of options)
i) Try save or update
ii) In Purchase just write simple getter and setter
iii) in pendingpayment mapping do cascade="save-update,delete"
iv) in test class do this
Purchase p = new Purchase();
p.setPendingPayment(new PendingPayment());

session.save(p);

///then

p.setPendingPayment(null);

session.save(p);

_________________
** Rate me if the solution was useful **

Regards,
Paras Jain


Top
 Profile  
 
 Post subject: Last try ---- corrections
PostPosted: Thu Aug 14, 2008 4:36 pm 
Beginner
Beginner

Joined: Thu Jan 13, 2005 10:50 am
Posts: 30
Location: Minneapolis, MN
Seems strange that saveOrUpdate also doesn't work

For this particular example try this(if this also doesn't work then I am out of options)
i) Try save or update
ii) In Purchase just write simple getter and setter
iii) in pendingpayment mapping do cascade="save-update,delete"
iv) in test class do this
Purchase p = new Purchase();
p.setPendingPayment(new PendingPayment());

session.saveOrUpdate(p);

///then

p.setPendingPayment(null);

session.saveOrUpdate(p);

_________________
** Rate me if the solution was useful **

Regards,
Paras Jain


Top
 Profile  
 
 Post subject: Re: Last try ---- corrections
PostPosted: Thu Aug 14, 2008 5:30 pm 
Newbie

Joined: Wed Aug 13, 2008 10:30 am
Posts: 11
parasjain01 wrote:
Seems strange that saveOrUpdate also doesn't work

For this particular example try this(if this also doesn't work then I am out of options)
i) Try save or update
ii) In Purchase just write simple getter and setter
iii) in pendingpayment mapping do cascade="save-update,delete"
iv) in test class do this
Purchase p = new Purchase();
p.setPendingPayment(new PendingPayment());

session.saveOrUpdate(p);

///then

p.setPendingPayment(null);

session.saveOrUpdate(p);


Okay, so I already had the getters and setters in Purchase class. In the PendingPayment, I modified the mapping for purchase field as follows:
Code:
    @OneToOne(mappedBy = "pendingPayment", optional = false)
@org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.DELETE,
        org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    Purchase purchase;


I changed my PurchaseTest class as following:
Code:
      Session session = HibernateUtil.getSessionFactory().openSession();
      Transaction tx = session.beginTransaction();
      
      Purchase purchase = new Purchase();
      purchase.setPendingPayment(new PendingPayment(purchase));
      session.saveOrUpdate(purchase);
      
      tx.commit();
      
      Transaction newTransaction = session.beginTransaction();
      
      purchase.setPendingPayment(null);
        session.saveOrUpdate(purchase);
      newTransaction.commit();
      
      session.close();


Still no delete sql generated/executed :(

Would the hibernate debug log help to try to figure out what is going on?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 14, 2008 5:41 pm 
Beginner
Beginner

Joined: Thu Jan 13, 2005 10:50 am
Posts: 30
Location: Minneapolis, MN
Code:
purchase.setPendingPayment(new PendingPayment(purchase));


Instead of this can you do the following

Code:
purchase.setPendingPayment(new PendingPayment());


you might have to create a no-arg constructor in PendingPayment, if not already there.

If that also doesn't work, then set show_sql to true and see whatz happening. may be hibernate is deleting first and after that it is re-associating and getting inserted.[/quote]

_________________
** Rate me if the solution was useful **

Regards,
Paras Jain


Top
 Profile  
 
 Post subject: Cascade annotation in Purchase class not PendingPayment
PostPosted: Thu Aug 14, 2008 5:44 pm 
Beginner
Beginner

Joined: Thu Jan 13, 2005 10:50 am
Posts: 30
Location: Minneapolis, MN
Also,
I think the cascade annotation should be in the Purchase class over PendingPending element

_________________
** Rate me if the solution was useful **

Regards,
Paras Jain


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 23 posts ]  Go to page 1, 2  Next

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.