-->
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.  [ 5 posts ] 
Author Message
 Post subject: Problem with Cascade
PostPosted: Wed Oct 20, 2010 9:32 am 
Newbie

Joined: Thu Apr 16, 2009 7:09 am
Posts: 13
Hi,

I seem to be having some trouble with relationships within hibernate. I have parent A, who has a collection of B, who in turn has a collection of C. I want to be able to always call session.update(a); and then even if nothing has changed on A or B, but it has on C, I want hibernate to be able to identify that one of its grandchildren has changed.

My question is, is hibernate able to detect this change through the use of the CascadeType's (or something similar).

Note, that I am using annotations, and hibernate-core version 3.3.2.GA.

Thanks in advance.

p.s. I have tried many combinations with the CascadeType's but I seem to be getting lost, and maybe this just isn't possible in the first place, so always good to ask


Top
 Profile  
 
 Post subject: Re: Problem with Cascade
PostPosted: Wed Oct 20, 2010 9:35 am 
Senior
Senior

Joined: Fri Oct 08, 2010 8:44 am
Posts: 130
So, are you saying that ALL does not work for you combined with "saveOrUpdate"?


Top
 Profile  
 
 Post subject: Re: Problem with Cascade
PostPosted: Wed Oct 20, 2010 10:17 am 
Newbie

Joined: Thu Apr 16, 2009 7:09 am
Posts: 13
I have tried ALL many times, but had to revert out of using it, because it doesn't always order things like the inserts properly, and then I find I have to start introducing OnDelete, and the Cascade's with proper values, because using the ALL everywhere seems to get Hibernate mixed up with the ordering of things.
Unless there are some simple things that I am missing from the annotations? Do you have an example of a more complicated structure mapped through hibernate (because all of the examples online are only basic ones)?

Much appreciated.


Top
 Profile  
 
 Post subject: Re: Problem with Cascade
PostPosted: Thu Oct 21, 2010 8:53 am 
Newbie

Joined: Thu Apr 16, 2009 7:09 am
Posts: 13
I have created a test case to highlight what I am seeing, but I see that I am unable to post a zip file here containing the test case. If anyone is interested in seeing the test case I can either post it all, or send it via email.

Let me post it here, so that you can see what I mean:

Code:
@Entity
@Table(name = "PARENT")
public class Parent implements Serializable {

   private static final long serialVersionUID = 1L;
   
   private Integer id;
   private String name;
   
   private Set<Child> children = new HashSet<Child>();
   

   /**
    *
    */
   public Parent() {
   }

   @Id
   @Column(name = "ID", nullable = false, precision = 8, scale = 0)
   @GeneratedValue(generator = "PARENT_SEQ", strategy = GenerationType.SEQUENCE)
   @SequenceGenerator(name = "PARENT_SEQ", sequenceName = "parent_seq", allocationSize = 1)
   public Integer getId() {
      return id;
   }

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

   @Column(name = "NAME_", length = 128)
   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "owner")
   public Set<Child> getChildren() {
      return children;
   }

   public void setChildren(Set<Child> children) {
      this.children = children;
   }

}


Code:
@Entity
@Table(name = "CHILD")
public class Child implements Serializable {

   private static final long serialVersionUID = 1L;
   
   private Integer id;
   private String name;
   private Parent owner;
   
   private Set<Grandchild> grandchildren = new HashSet<Grandchild>();

   /**
    *
    */
   public Child() {
   }

   @Id
   @Column(name = "ID", nullable = false, precision = 8, scale = 0)
   @GeneratedValue(generator = "CHILD_SEQ", strategy = GenerationType.SEQUENCE)
   @SequenceGenerator(name = "CHILD_SEQ", sequenceName = "child_seq", allocationSize = 1)
   public Integer getId() {
      return id;
   }

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

   @Column(name = "NAME_", length = 128)
   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "OWNER_ID", nullable = false)
   public Parent getOwner() {
      return owner;
   }

   public void setOwner(Parent owner) {
      this.owner = owner;
   }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "owner")
   public Set<Grandchild> getGrandchildren() {
      return grandchildren;
   }

   public void setGrandchildren(Set<Grandchild> grandchildren) {
      this.grandchildren = grandchildren;
   }

}


Code:
@Entity
@Table(name = "GRANDCHILD")
public class Grandchild implements Serializable {

   private static final long serialVersionUID = 1L;
   
   private Integer id;
   private String name;
   private Child owner;

   /**
    *
    */
   public Grandchild() {
   }

   @Id
   @Column(name = "ID", nullable = false, precision = 8, scale = 0)
   @GeneratedValue(generator = "GRANDCHILD_SEQ", strategy = GenerationType.SEQUENCE)
   @SequenceGenerator(name = "GRANDCHILD_SEQ", sequenceName = "grandchild_seq", allocationSize = 1)
   public Integer getId() {
      return id;
   }

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

   @Column(name = "NAME_", length = 128)
   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "OWNER_ID", nullable = false)
   public Child getOwner() {
      return owner;
   }

   public void setOwner(Child owner) {
      this.owner = owner;
   }

}


Code:
<hibernate-configuration>

   <session-factory>
      <property name="hibernate.connection.autocommit">false</property>
      
      <mapping class="testcases.model.Parent"/>
      <mapping class="testcases.model.Child"/>
      <mapping class="testcases.model.Grandchild"/>
      
   </session-factory>

</hibernate-configuration>


And now here is the test (written in TestNG):

Code:
public class Testing {

   /**
    *
    */
   public Testing() {
      // TODO Auto-generated constructor stub
   }

   @BeforeSuite
   public void setup() {
      HibernateUtils.getInstance().createDatabase();
   }
   
   @BeforeTest
   public void setupData() {
      Session session = HibernateUtils.getInstance().getNewSession();
      session.beginTransaction();
      for (int i=0; i<10; i++) {
         Parent parent = new Parent();
         parent.setName("Parent_" + i);
         for (int j=0; j<10; j++) {
            Child child = new Child();
            child.setName("Child_" + j);
            child.setOwner(parent);
            parent.getChildren().add(child);
            for (int k=0; k<10; k++) {
               Grandchild grandchild = new Grandchild();
               grandchild.setName("Grandchild_" + k);
               grandchild.setOwner(child);
               child.getGrandchildren().add(grandchild);
            }
         }
         session.persist(parent);
      }
      session.getTransaction().commit();
      session.flush();
   }
   
   @Test
   public void test1() {
      Assert.assertTrue(ensureParentCount(10));
      Assert.assertTrue(ensureChildCount(10 * 10));
      Assert.assertTrue(ensureGrandchildCount(10 * 10 * 10));
      
      Session session = HibernateUtils.getInstance().getNewSession();
      session.beginTransaction();
      
      Parent parent = (Parent) session.createCriteria(Parent.class).add(Restrictions.eq("name", "Parent_5")).uniqueResult();
      Child child = (Child) session.createFilter(parent.getChildren(), "WHERE this.name = :PARAM0").setString("PARAM0", "Child_5").uniqueResult();
      
      List<Grandchild> grandchildren = new ArrayList<Grandchild>(child.getGrandchildren());
      for (int i=0; i<5; i++) {
         child.getGrandchildren().remove(grandchildren.get(i));
      }
      session.update(parent);
      session.getTransaction().commit();
      session.flush();
      Assert.assertTrue(ensureGrandchildCount((10 * 10 * 10) - 5));
   }
   
   
   private boolean ensureParentCount(int count) {
      Session session = HibernateUtils.getInstance().getNewSession();
      try {
         return session.createCriteria(Parent.class).list().size() == count;
      } finally {
         session.close();
      }
   }

   private boolean ensureChildCount(int count) {
      Session session = HibernateUtils.getInstance().getNewSession();
      try {
         return session.createCriteria(Child.class).list().size() == count;
      } finally {
         session.close();
      }
   }

   private boolean ensureGrandchildCount(int count) {
      Session session = HibernateUtils.getInstance().getNewSession();
      try {
         return session.createCriteria(Grandchild.class).list().size() == count;
      } finally {
         session.close();
      }
   }


As you can see from the test, I am trying to remove 5 grandchildren, and then execute the save, but it doesn't pick up that there is a change, and the last test fails.


Top
 Profile  
 
 Post subject: Re: Problem with Cascade
PostPosted: Thu Oct 21, 2010 1:24 pm 
Senior
Senior

Joined: Fri Oct 08, 2010 8:44 am
Posts: 130
As far as I see from your description cascade does work perfectly and indeed updates everything correctly. It is your checks to blame.

You posted the following code:

Code:
      for (int i=0; i<5; i++) {
         child.getGrandchildren().remove(grandchildren.get(i));
      }


This code does not remove anything from grandchildren table. It just disconnects that children from their appropriate parent. That why total count of records does not change. To remove the children from the table you have to directly say this to your persister. As alternative you may, for example, use DELETE_ORPHAN cascade type on the list.


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