-->
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.  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: all-delete-orphan with detached objects
PostPosted: Fri Feb 11, 2005 9:56 pm 
Newbie

Joined: Fri Feb 04, 2005 11:39 pm
Posts: 13
Hi,
My application has a web ui with a long form showing parent object information and multiple children objects (with one-to-many association). The application is supposed to update, insert and even delete one or more children objects if the user clears all their fields.

I am using detached objects. Although I can persist newly created children objects as well as changes to the existing children objects, I am not able to delete children objects by simply removing them form the Set (mapped as one to many and all-delete-orphan).

I remove the children objects in a detached state.

Is all-delete-orpahn possible for detched objects?

Regards
Anil


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 11, 2005 10:06 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
yes.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 14, 2005 4:19 am 
Newbie

Joined: Fri Feb 04, 2005 11:39 pm
Posts: 13
Hi Gavin,
Thanks for replying.
I thought so, but I am not able to delete children objects (with parent to children one to many relationship). My code removes the children objects (from the persistent set) while the object is in a detached state.

I just open the session and pass the initially detached object to the update method.

I am using update method because the parent object is always upadated (never inserted or deleted). I have declared cascade option as all-delete-orphan.

Please let me know if I am missing something.

I am using Orion (Shipped with oracle application server). Web layer calls a stateless session facade, which in turn calls Hibernate.

Earlier I noticed that automatic flush was not happening on calling transaction.commit() due which even simple update was not working.

I fixed that problem by explicitly flushing the session after every hibernate transaction commit, but I am still not able to accomplish automatic deletion of children removed in detached state, even with all-delete-orphan cascade option. Please note that insertion and update of children objects works fine. I am using hibernate 3.0 beta 1.0
Regards
Anil


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 14, 2005 4:36 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Quote:
Earlier I noticed that automatic flush was not happening on calling transaction.commit()


Then you have much bigger problems than orphan delete not working. I advise you to fix the basics first, then go onto more exotic things.

Quote:
I am using hibernate 3.0 beta 1.0


We are now on beta4b.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 14, 2005 5:15 am 
Newbie

Joined: Fri Feb 04, 2005 11:39 pm
Posts: 13
Hi Gavin,
The flush() problem has already been fixed. I moved on to all-delete-orphan only after fixing the basic problem.

Please note that I am not trying the all-delete-orphan feature (with detached objects) just because it's an exotic feature, It's a genunine application requirement. In our earlier project with ejb 2.x, we had to do this kind of coding on our own and I am excited about this particular feature because it could save us a lot of error prone coding.

Now that I have fixed those basic flush problems and even update and insert of detached objects works fine, could you please let me know if I am missing something ?

For your quick refercne, I would summarize what I am doing:

(a) Parent to child has one to many relationships, with cascade option as "all-delete-orphan" and lazy="false".
(b) Parent is loaded along with children, the session is closed and sent to the web layer.
(c) If the user enters a new child object, we create a new persistent object and add it to the Set (off course with id as null). If a child is updated, we just update the value and if a child is cleared, we just remove the child object from the Set.
(d) The modified parent object as sent back to session facade, which calls session.update() and passes the modified object to this method.

(e) The newly created children objects are inserted, the updated objects are updated, but the removed obejects are not deleted

I would use the latest beta.


Top
 Profile  
 
 Post subject: orphan delete example
PostPosted: Mon Feb 14, 2005 8:15 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
I'm sorry, I can't tell you what you are doing wrong when you show no code. But todays your lucky day 'cos i realized I didnt have a nicely formatted test for this so I wrote one up. You can see what you're *meant* to be doing and work from there:

Code:
<hibernate-mapping package="org.hibernate.test.orphan">

   <class name="Product">
      <id name="name"/>
      <set name="parts" cascade="all,delete-orphan" fetch="join">
         <key column="productName" not-null="true"/>
         <one-to-many class="Part"/>
      </set>
   </class>
   
   <class name="Part">
      <id name="name"/>
      <property name="description" not-null="true"/>
   </class>

</hibernate-mapping>


Code:
public class Product {
   private String name;
   private Set parts = new HashSet();
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public Set getParts() {
      return parts;
   }
   public void setParts(Set parts) {
      this.parts = parts;
   }
}


Code:
public class Part {
   private String name;
   private String description;
   public String getDescription() {
      return description;
   }
   public void setDescription(String description) {
      this.description = description;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}


Code:
public class OrphanTest extends TestCase {
   
   public OrphanTest(String str) {
      super(str);
   }
   
   public void testOrphanDeleteOnSaveOrUpdate() {
      Session session = openSession();
      Transaction t = session.beginTransaction();
      Product prod = new Product();
      prod.setName("Widget");
      Part part = new Part();
      part.setName("Widge");
      part.setDescription("part if a Widget");
      prod.getParts().add(part);
      Part part2 = new Part();
      part2.setName("Get");
      part2.setDescription("another part if a Widget");
      prod.getParts().add(part2);
      session.create(prod);
      t.commit();
      session.close();
      
      prod.getParts().remove(part);
      
      session = openSession();
      t = session.beginTransaction();
      session.saveOrUpdate(prod);
      t.commit();
      session.close();
      
      session = openSession();
      t = session.beginTransaction();
      assertNull( session.get(Part.class, "Widge") );
      assertNotNull( session.get(Part.class, "Get") );
      session.delete( session.get(Product.class, "Widget") );
      t.commit();
      session.close();
   }
   
   public void testOrphanDelete() {
      Session session = openSession();
      Transaction t = session.beginTransaction();
      Product prod = new Product();
      prod.setName("Widget");
      Part part = new Part();
      part.setName("Widge");
      part.setDescription("part if a Widget");
      prod.getParts().add(part);
      Part part2 = new Part();
      part2.setName("Get");
      part2.setDescription("another part if a Widget");
      prod.getParts().add(part2);
      session.create(prod);
      t.commit();
      session.close();
      
      session = openSession();
      t = session.beginTransaction();
      prod = (Product) session.get(Product.class, "Widget");
      assertTrue( Hibernate.isInitialized( prod.getParts() ) );
      part = (Part) session.get(Part.class, "Widge");
      prod.getParts().remove(part);
      t.commit();
      session.close();
      
      session = openSession();
      t = session.beginTransaction();
      assertNull( session.get(Part.class, "Widge") );
      assertNotNull( session.get(Part.class, "Get") );
      session.delete( session.get(Product.class, "Widget") );
      t.commit();
      session.close();
   }
   
   public void testOrphanDeleteOnMerge() {
      Session session = openSession();
      Transaction t = session.beginTransaction();
      Product prod = new Product();
      prod.setName("Widget");
      Part part = new Part();
      part.setName("Widge");
      part.setDescription("part if a Widget");
      prod.getParts().add(part);
      Part part2 = new Part();
      part2.setName("Get");
      part2.setDescription("another part if a Widget");
      prod.getParts().add(part2);
      session.create(prod);
      t.commit();
      session.close();
      
      prod.getParts().remove(part);
      
      session = openSession();
      t = session.beginTransaction();
      session.merge(prod);
      t.commit();
      session.close();
      
      session = openSession();
      t = session.beginTransaction();
      assertNull( session.get(Part.class, "Widge") );
      assertNotNull( session.get(Part.class, "Get") );
      session.delete( session.get(Product.class, "Widget") );
      t.commit();
      session.close();
   }
   
   
   protected String[] getMappings() {
      return new String[] { "orphan/Product.hbm.xml" };
   }

   public static Test suite() {
      return new TestSuite(OrphanTest.class);
   }

}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 14, 2005 8:16 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
(of course, in a real app you are meant to implement equals() and hashCode() if you are going to put detached objects in Sets)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 15, 2005 4:49 am 
Hi,
Even i had the same problem of child objects not getting deleted in case of detached objects, while using all-delete-orphan. I found out that:

###########################################
Unlike other Hibernate value types, Hibernate tracks actual collection instances using Java identity, ==. Your getter method should return the same collection instance as was assigned by Hibernate to the setter method
###########################################
http://hibernate.org/116.html

So, i started keeping references of the Set returned by Hibernate. I then replaced the elements in this set as required. Then, the all-delete-orphan
feature started working with detached objects.
Below is the link which talks of the same problem:

http://forum.hibernate.org/viewtopic.ph ... highlight=


Top
  
 
 Post subject:
PostPosted: Wed Feb 16, 2005 9:16 pm 
Newbie

Joined: Fri Feb 04, 2005 11:39 pm
Posts: 13
Hi Gavin, Jaikiran,
Thanks a lot for your responses.

Gavin, thanks a lot for the detailed example. I made sure my code does exactly what you are doing with the only difference that my detached POJOs are returned to the web layer by a stateless session facade and rendered by jsps (I am using struts). I recreate the POJOs when the user submits the form. That is the lweb layer creates new POJOs with the data submitted by the user, which is sent over to the Sesion facade. I re-attach the POJOs by calling session.update() or session.saveorUpdate() (I tried both).




I populate the newly created parent object with a new Set (Hashset is the implementation).

I am still not able to delete the children objects. (though insert and update of children objects works fine.

Jaikiran, I am not sure what do you mean when you say you keep the same Set reference. Isn't the reference lost anyway when you close and flush the hibernate session. Do you mean to say that we should use the same Set implementation that Hibernate originally loads?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 16, 2005 10:09 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
anilkumarbhatt2 wrote:
I recreate the POJOs when the user submits the form.


Don't do that. Reuse the original instances.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 16, 2005 10:41 pm 
Newbie

Joined: Fri Feb 04, 2005 11:39 pm
Posts: 13
Hi Gavin,

Looks like I can't use the original instances.

Reason 1: Although I am passing the original POJOS to the web layer, as per our our architecture/design, these POJOs have a request scope in the web layer. So, these objects are forgotten as soon as the web page is rendered.

Struts recreates and populates the POJOs automatically again when the user submits the form.

Reason 2: In the actual application, we will need to use DTOs. Although I don't like DTOs and would have preferred POJOs, our views are "weird" and do not reflect the domain hierarchy at all.

Also, could you please explain why do I have to use the original objects? (update and insert seem to work fine).

Please bear with me as I am a Hibernate novice :-)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 16, 2005 10:52 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
(1) stick them in the HttpSession

(2) you have to do this because the collection caches the old state, this is how Hibernate knows how which orphans to delete

(3) your proposed approach will never work with any ORM solution that supports detachement, you are completely forgetting about the fact that these "objects" are just part of a huge object graph consisting of many lazily fetched associations that you have no chance of being able to reconstruct at the start of a request. You would end up trying to assign "null" to non-null associations, and wreaking havoc

(4) detachment is an ALTERNATIVE to DTO. You do not, ever, use them simultaneously, that makes no sense


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 16, 2005 11:08 pm 
Newbie

Joined: Fri Feb 04, 2005 11:39 pm
Posts: 13
Hi Gavin,
please let me know If I understood you correctly:

1. With DTOs, I'll need to load the objects and set the appropriate values from the DTOs to POJOs while they are attached.

2. Will it be an issue only for deletes (as I mentioned earlier, I could still accomplish transitive update and insert for children objects even though I did not use the original objects).?

3. My main objective is to pass on the parent object to Hibernate and let it figure out which children objects need to be inserted, updated or deleted. Can I still accomplish it if i am using DTOs (and consequently attched objects).


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 16, 2005 11:16 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Your question is bold does not make sense.

You do not use detached objects if you are using DTOs.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 16, 2005 11:26 pm 
Newbie

Joined: Fri Feb 04, 2005 11:39 pm
Posts: 13
Thanks Gavin,
We will use DTOs and hence attached objects (that was an eye opener).
Looking forward to bug you in future too :-)


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