-->
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.  [ 10 posts ] 
Author Message
 Post subject: Order for cascading actions?
PostPosted: Fri Jan 04, 2008 12:53 pm 
Beginner
Beginner

Joined: Thu Nov 15, 2007 11:27 am
Posts: 34
Hello,

Happy new years 2008!!!

After hollydays, a co-worker comes to me with a problem on cacasding and constraint violation.

During the comit, the cascading (all-delete-orphan) try to insert before deleting the table row, so we run into a constraint violation (a dedicated unique constraint added on a table).

Is it possible to force the cascading commands order?
(so we can delete before inserting/updating rows)

Thanks,
Yoann.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 06, 2008 7:46 pm 
Expert
Expert

Joined: Mon Nov 26, 2007 2:29 pm
Posts: 443
Yoann,

I would assume that the Hibernate people foresaw this very common scenario you are describing, and therefore the problem must lie in your code somewhere. Can you provide a little more information, such as classes, tables, mappings or test client code?

_________________
Gonzalo Díaz


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 06, 2008 8:18 pm 
Newbie

Joined: Sun Jan 06, 2008 8:11 pm
Posts: 6
I think this problem is similar to the one I have.

A class called 'Parent' has a set of 'Child' classes.

The mappings are set correctly with the cascade="all" option such that when a 'Parent' class is deleted, all the 'Child' instances of that parent are deleted as well.

My problem is that on calling 'session.flush()' an errors occurred since Hibernate tries to set the column 'parent_id' in my 'Child' table in the database to NULL. Since I have a constraint in my database that the column cannot e null, an exception crops up.

This problem can be easily fixed by removing the constraint from the database. In fact, I have tried that, and everything works as expected. However, I would appreciate if anyone could help me with a smarter solution.

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 07, 2008 1:33 am 
Expert
Expert

Joined: Mon Nov 26, 2007 2:29 pm
Posts: 443
Does the child exist as an independent entity, of just as a child?
When you delete the parent, did you first attempt to delete the relationship? What about the child itself?

Notice that in the scenario you describe, chrismic, there is an UPDATE going on. This wouldn't be happening unless you specifically intended to destroy the relationship between parent and child rather or before the child itself.

If you are to destroy the parent and the children don't have independent existence, just delete the parent and let Hibernate take care of the cascade.
If, on the contrary, the children can exist independently, then you cannot set the parent_id column to NOT NULL.

_________________
Gonzalo Díaz


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 07, 2008 5:30 am 
Newbie

Joined: Sun Jan 06, 2008 8:11 pm
Posts: 6
Hi gonzao, thanks for your reply. No, the child cannot exist independently (hence, the column is set to NOT NULL in the database).

All I am doing is a simple:

session.delete(parent);
.
.
.
session.flush();
session.connection.commit();
session.close();

The exception is given on the .flush()


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 07, 2008 6:30 am 
Beginner
Beginner

Joined: Thu Nov 15, 2007 11:27 am
Posts: 34
Ok I reproduce it "simply" with 3 tables:
create table table1 (ID INTEGER NOT NULL DEFAULT SERIAL)
create table table2 (ID INTEGER NOT NULL DEFAULT SERIAL, idtable1 INTEGER NOT NULL, idtable2 INTEGER NOT NULL)
create table table3 (ID INTEGER NOT NULL DEFAULT SERIAL)
alter table table2 add constraint constr unique (idtable1, idtable3)

Mapping (3 files Table1.hbm.xml, ...):
Code:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="org.test.datamodel.Table1" table="TABLE1" schema="MYDB">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="increment" />
        </id>
        <set name="idtable2" inverse="true" cascade="all-delete-orphan">
            <key>
                <column name="idtable1" not-null="true" />
            </key>
            <one-to-many class="org.test.datamodel.Table2" />
        </set>
    </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="org.test.datamodel.Table2" table="TABLE2" schema="MYDB">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="increment" />
        </id>
        <many-to-one name="idtable1" class="org.test.datamodel.Table1" fetch="select" unique-key="constr">
            <column name="idtable1" not-null="true" />
        </many-to-one>
        <many-to-one name="idtable3" class="org.test.datamodel.Table3" fetch="select" unique-key="constr">
            <column name="idtable3" not-null="true" />
        </many-to-one>
    </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="org.test.datamodel.Table3" table="TABLE3" schema="MYDB">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="increment" />
        </id>
        <set name="idtable2" inverse="true">
            <key>
                <column name="idtable3" not-null="true" />
            </key>
            <one-to-many class="org.test.datamodel.Table2" />
        </set>
    </class>
</hibernate-mapping>


Bean:
Code:
package org.test.datamodel;

import java.util.Set;

public class Table1 implements java.io.Serializable {
   
    /**
    * serial version UID
    */
   private static final long serialVersionUID = 1L;

   // Fields   

   private Integer id;
   private Set idtable2;

   public Table1() {
   }

   public Integer getId() {
      return id;
   }

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

   public Set getIdtable2() {
      return idtable2;
   }

   public void setIdtable2(Set idtable2) {
      this.idtable2 = idtable2;
   }

}

package org.test.datamodel;

public class Table2 implements java.io.Serializable {
   
    /**
    * serial version UID
    */
   private static final long serialVersionUID = 1L;

   // Fields   

   private Integer id;
   private Table1 idtable1;
   private Table3 idtable3;

   public Table2() {
   }

   public Integer getId() {
      return id;
   }

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

   public Table1 getIdtable1() {
      return idtable1;
   }

   public void setIdtable1(Table1 idtable1) {
      this.idtable1 = idtable1;
   }

   public Table3 getIdtable3() {
      return idtable3;
   }

   public void setIdtable3(Table3 idtable3) {
      this.idtable3 = idtable3;
   }

}

package org.test.datamodel;

import java.util.Set;

public class Table3 implements java.io.Serializable {
   
    /**
    * serial version UID
    */
   private static final long serialVersionUID = 1L;

   // Fields   

   private Integer id;
   private Set idtable2;

   public Table3() {
   }

   public Integer getId() {
      return id;
   }

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

   public Set getIdtable2() {
      return idtable2;
   }

   public void setIdtable2(Set idtable2) {
      this.idtable2 = idtable2;
   }

}


Junit test:
Code:
   public void testThat(){
      Configuration cfg = new org.hibernate.cfg.Configuration();
      Properties hibProp = new Properties();
      
      try {
         String url = "jdbc:sapdb://mezzo:7210/use_yja";
         String user = "yja";
         String password = "yja";
         Class.forName("com.sap.dbtech.jdbc.DriverSapDB");
         Connection connection = DriverManager.getConnection(url, user, password);
   
         hibProp.load(new FileInputStream(new File("D:/workspaceV4/webapp/WEB-INF/classes/hibernate.properties")));
         cfg = cfg.addProperties(hibProp);
         SessionFactory sf = cfg.configure(new File("D:/workspaceV4/test/hibernate.cfg.xml")).buildSessionFactory();
         Session session = sf.openSession(connection);
         
         session.beginTransaction();
         
         Table1 table1 = (Table1) session.load(Table1.class, new Integer(2));
         Table2 table2 = (Table2)table1.getIdtable2().iterator().next();
//remove an object
         table1.getIdtable2().remove(table2);
         Table2 newTable2 = new Table2();
         newTable2.setIdtable1(table2.getIdtable1());
         newTable2.setIdtable3(table2.getIdtable3());
//add a new object with the same secondary key
         table1.getIdtable2().add(newTable2);
         table2 = null;
         
         session.getTransaction().commit();
      } catch (RuntimeException re) {
         throw re;
      } catch (Exception e) {
         System.out.println(e.toString());
      }
   }


The cascade produce the following commands:
Code:
Hibernate:
    select
        table1x0_.ID as ID0_0_
    from
        MYDB.TABLE1 table1x0_
    where
        table1x0_.ID=?
Hibernate:
    select
        idtable2x0_.ID as ID1_,
        idtable2x0_.ID as ID1_0_,
        idtable2x0_.idtable1 as idtable2_1_0_,
        idtable2x0_.idtable3 as idtable3_1_0_
    from
        MYDB.TABLE2 idtable2x0_
    where
        idtable2x0_.ID=?
Hibernate:
    select
        max(ID)
    from
        TABLE2
Hibernate:
    insert
    into
        MYDB.TABLE2
        (idtable1, idtable3, ID)
    values
        (?, ?, ?)
Hibernate:
    delete
    from
        MYDB.TABLE2
    where
        ID=?

If the constraint is set in the data base, the insert failed.

If the delete is done before the insert, everything will be OK.



edit: I've been redirected to http://forum.hibernate.org/viewtopic.php?t=934483 so it seems to be an old issue that the team don't want to solve for some unclear reason to me... I guess the answer to my first post is "NO".


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 07, 2008 11:40 am 
Expert
Expert

Joined: Mon Nov 26, 2007 2:29 pm
Posts: 443
Yoann,

That desing looks too tangled.
Let me see if I understand what you want here:

- Table1 has a many-to-many relationship to Table3.
- Table2 is just a connection table between the other two tables.
- All your relationships are bi-directional (i.e., you can"set parents to a child")


Are these 3 statement correct? Confirm and we go from there.

_________________
Gonzalo Díaz


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 07, 2008 12:14 pm 
Newbie

Joined: Wed Aug 23, 2006 7:59 am
Posts: 7
chrismic wrote:
Hi gonzao, thanks for your reply. No, the child cannot exist independently (hence, the column is set to NOT NULL in the database).

All I am doing is a simple:

session.delete(parent);
.
.
.
session.flush();
session.connection.commit();
session.close();

The exception is given on the .flush()


I had the same problem as you have...

this post http://forum.hibernate.org/viewtopic.php?t=980469 solved it for me.

hope it helps you as well,

Willem


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 07, 2008 12:47 pm 
Beginner
Beginner

Joined: Thu Nov 15, 2007 11:27 am
Posts: 34
gonzao_diaz wrote:
Yoann,

That desing looks too tangled.
Let me see if I understand what you want here:

- Table1 has a many-to-many relationship to Table3.

Yes.
Quote:
- Table2 is just a connection table between the other two tables.

No, table2 contains normaly other information, but I simplify it for the example.
Quote:
- All your relationships are bi-directional (i.e., you can"set parents to a child")
Are these 3 statement correct? Confirm and we go from there.

Yes they are all bidirectional.

Actually table 2 is part of a n-aire relation on 4 tables. (Note: I did not design the data base :D )


As far as I understand, the order of cascade operation will not be changed, so I got a turn around that consists on saving the object from the set in a temporary set, doing a clear on the set, forcing a session.flush() and put back the object in the set. Bad thing is that I got new Id on object that haven't change.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 07, 2008 1:38 pm 
Expert
Expert

Joined: Mon Nov 26, 2007 2:29 pm
Posts: 443
Quote:
an n-aire relationship of 4 tables ...


Sorry, Yoann, I have to give up on this one.

_________________
Gonzalo Díaz


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