From: <leg...@at...> - 2003-12-09 22:27:19
|
Message: The following issue has been closed. Resolver: Gavin King Date: Tue, 9 Dec 2003 4:26 PM You have one instance variable which is used by to two different properties, one on the superclass, one on the subclass. Please use the user forum for these kind of problems. JIRA is for bugs in Hibernate. --------------------------------------------------------------------- View the issue: http://opensource.atlassian.com/projects/hibernate/secure/ViewIssue.jspa?key=HB-533 Here is an overview of the issue: --------------------------------------------------------------------- Key: HB-533 Summary: Bidirectional Parent / Child relationship between a class and a joined-subclass gets deleted by saveOrUpdate Type: Bug Status: Closed Priority: Minor Resolution: REJECTED Project: Hibernate2 Components: core Versions: 2.1 rc1 Assignee: Gavin King Reporter: Gary Miller Created: Tue, 9 Dec 2003 8:50 AM Updated: Tue, 9 Dec 2003 4:26 PM Environment: JDK 1.4.0-b92 postgres 7.3.4 Description: The child to parent reference get set to null when an existing graph is retrieved from the DB and then saveOrUpdate is called with no changes made to the graph. The following example illustrates the point. There is a work around which is to effectively disable the setParent method if the parent provided is null. This section of code is commented out in the example. I have run this code up in a debugger but don't know how to debug a cglib generated class. I new to hibernate, please let me know how I could have improved my post. Regards Gary Miller Class hierarchy Model | --------- | | Root NodeElem | ----------- | | Node Leaf Object Graph root -> nodes node -> nodeelems All these relationships are bidirectional Therefore a node's parent can either be a Root or a NodeElem. Mapping File test.hbm.xml <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="net.sf.hibernate.examples.Root" table="eg_root" dynamic-update="false" dynamic-insert="false"> <id name="id" column="id" type="java.lang.String" unsaved-value="null"> <generator class="uuid.hex"/> </id> <version name="version" type="int" column="version"/> <bag name="nodes" lazy="false" inverse="true" cascade="save-update"> <key column="root_id"/> <one-to-many class="net.sf.hibernate.examples.Node"/> </bag> </class> <class name="net.sf.hibernate.examples.NodeElem" table="eg_nodeelem" dynamic-update="false" dynamic-insert="false"> <id name="id" column="id" type="java.lang.String" unsaved-value="null"> <generator class="uuid.hex"/> </id> <version name="version" type="int" column="version"/> <many-to-one name="parentNodeElem" column="node_id" not-null="false" cascade="save-update"/> <joined-subclass name="net.sf.hibernate.examples.Node" table="eg_node" dynamic-update="false" dynamic-insert="false"> <key column="id"/> <many-to-one name="parentRoot" column="root_id" not-null="false" cascade="save-update"/> <bag name="nodeElem" table="NodeElem" lazy="false" inverse="true" cascade="save-update"> <key column="node_id"/> <one-to-many class="net.sf.hibernate.examples.NodeElem"/> </bag> </joined-subclass> <joined-subclass name="net.sf.hibernate.examples.Leaf" table="eg_leaf" dynamic-update="false" dynamic-insert="false"> <key column="id"/> <property name="name" type="java.lang.String" update="true" insert="true" column="name"/> </joined-subclass> </class> </hibernate-mapping> Test Classes sf.net.hibernate.example.Main ----------------------------- package net.sf.hibernate.examples; import java.util.Iterator; import net.sf.hibernate.Query; import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Transaction; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.cfg.Environment; /** * @author garym * Main */ public class Main { static void print( Root r ) { System.out.println( r ); for( Iterator it = r.getNodes().iterator() ; it.hasNext() ; ) { Node n = (Node) it.next(); recurseNode( n , "\t" ); } } static void recurseNode( Node n , String pretty ) { System.out.println( pretty + n.toString() + "\t parent:" + n.getParent() ); for( Iterator it2 = n.getNodeElem().iterator(); it2.hasNext() ; ) { NodeElem ne = (NodeElem) it2.next(); if( ne instanceof Node ) recurseNode( (Node) ne , pretty + "\t" ); else System.out.println( pretty + "\t" + ne.toString() + "\t parent:" + ne.getParent() ); } } public static void main(String[] args) throws Exception { SessionFactory sessionFactory = new Configuration() .configure( "/net/sf/hibernate/examples/hibernate.cfg.xml" ) // .setProperty(Environment.HBM2DDL_AUTO, "create") .buildSessionFactory(); // for( int i = 0 ; i < 1 ; i++ ) { Session session = sessionFactory.openSession(); // Root r = null; Query query = session.createQuery("select r from Root as r"); Iterator it = query.iterate(); if( it.hasNext() ) { r = (Root) it.next(); System.out.println("Retrieved" ); Iterator it2 = r.getNodes().iterator(); if( it2.hasNext() ) { Node n = (Node) it2.next(); Node n2 = new Node(); n2.addNodeElem( new Leaf("new") ); n.addNodeElem( n2 ); } print(r); } else { System.out.println("No Root found" ); r = new Root(); Node n = new Node(); n.addNodeElem( new Leaf("Moe") ); n.addNodeElem( new Leaf("Curly") ); n.addNodeElem( new Leaf("Larry") ); r.addNode( n ); print( r ); } Transaction xaction= session.beginTransaction(); System.out.println("Started Trans" ); session.saveOrUpdate(r); System.out.println("Saved" ); xaction.commit(); System.out.println("Committed" ); session.close(); } sessionFactory.close(); } } Model ----- package net.sf.hibernate.examples; /** * @author garym * Model */ public class Model { String id; int ver; Model parent; void setParent( Model p ) { // THIS IS THE WORK AROUND // if( p == null ) { ////// parent = null; // return; // } if( parent != null && !p.equals(parent) ) throw new RuntimeException("Parent can only be set twice \nthis:'"+this+"'\nparent:'" + p + "'"); parent = p; } Model getParent( ) { return parent; } void setVersion( int v ) { ver = v; } int getVersion() { return ver; } void setId( String id ) { this.id = id; } String getId() { return id; } } Root ---- package net.sf.hibernate.examples; import java.util.ArrayList; import java.util.List; /** * @author garym * Root */ public class Root extends Model { List nodes; Root() {}; List getNodes() { return nodes; } void setNodes( List nodes ) { this.nodes = nodes; } void addNode( Node c ) { if(nodes == null) nodes = new ArrayList(); nodes.add(c); c.setParent( this ); } // public String toString() { // return nodes == null ? "[]" : nodes.toString(); // } } NodeElem -------- package net.sf.hibernate.examples; /** * @author garym */ public class NodeElem extends Model { void setParentNodeElem( NodeElem p ) { setParent(p); } NodeElem getParentNodeElem() { return (NodeElem) getParent(); } } Node ---- package net.sf.hibernate.examples; import java.util.ArrayList; import java.util.List; /** * @author garym */ public class Node extends NodeElem { List nodeElems; Node() {}; void setParentRoot( Root p ) { setParent(p); } Root getParentRoot() { Model p = getParent(); if( p instanceof Root ) return (Root) p; return null; } NodeElem getParentNodeElem() { Model p = getParent(); if( p instanceof NodeElem ) return (NodeElem) p; return null; } List getNodeElem() { return nodeElems; } void setNodeElem( List nodeElems ) { this.nodeElems = nodeElems; } void addNodeElem( NodeElem c ) { if(nodeElems == null) nodeElems = new ArrayList(); nodeElems.add(c); c.setParent( this ); } // public String toString() { // return nodeElems == null ? super.toString() + "[]" : super.toString() + nodeElems.toString(); // } } Leaf ---- package net.sf.hibernate.examples; /** * @author garym * Child */ public class Leaf extends NodeElem { String name; Leaf() {} Leaf( String name ) { setName(name); } void setName( String name ) { this.name = name; } String getName() { return name; } public String toString() { return "name:'" + name + "'"; } } --------------------------------------------------------------------- JIRA INFORMATION: This message is automatically generated by JIRA. If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa If you want more information on JIRA, or have a bug to report see: http://www.atlassian.com/software/jira |