-->
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.  [ 6 posts ] 
Author Message
 Post subject: Problem w child foreign key referring to parent primary key
PostPosted: Wed Apr 23, 2008 4:39 pm 
Newbie

Joined: Fri Mar 21, 2008 12:32 pm
Posts: 9
PROBLEM STATEMENT

I am trying to create a parent-child child relationship using hibernate 3.3.1 on MySql 5.0. Parent table has 2 fields ID and Name, ID is integer and the primary key, Name is a VARCHAR (30). Child table has 3 fields, ID, Name, and Parent_Id. ID is integer and the primary key, Name is VARCHAR(30), and Parent_Id is an integer and a foreign key which references Parent's ID

What I want is, the Parent_ID value in the Child class should be populated automatically along with the ID in the PARENT table because it is the foreign key to the ID in Parent's table. But it is not happening and a null value for the foreign key goes to the MySQL and the database complains. (The foreign key cannot be null in this application) Is there a way we can link the foreign key in the child table so that it is automatically populated with the value of the key it is linked to?


Mapping documents
Parent.hbm.xml
Code:
<hibernate-mapping>
   <class name="entities.Parent" table="parent" >
      <id name="id" column="id" type="int">
         <generator class="increment"/>
      </id>
      <property name="name" />
      <set name="children" inverse="true" cascade="all">
      <key column="parent_id"/>
      <one-to-many class="entities.Child"/>
      </set>
   </class>
</hibernate-mapping>

Child.hbm.xml
Code:
<hibernate-mapping>
   <class name="entities.Child" table="child">
      <id name="id" column="id" type="int" >
         <generator class="increment"/>
      </id>
      <property name="name" />
      <property name="parent_id"/>
   </class>
</hibernate-mapping>


hibernate.cfg.xml
Code:
<hibernate-configuration>
<session-factory>
      <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
      <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatetutorial</property>
      <property name="hibernate.connection.username">root</property>
      <property name="hibernate.connection.password">root</property>
      <property name="hibernate.connection.pool_size">10</property>
      <property name="show_sql">true</property>
      <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
      <property name="hibernate.hbm2ddl.auto">update</property>
      <!-- Mapping files -->
      <mapping resource="parent.hbm.xml"/>
      <mapping resource="child.hbm.xml"/>
</session-factory>
</hibernate-configuration>
[/b]

Code of the Child Object
Code:
package entities;

public class Child {
   private String name = null;
   private int id = -1;
   private int parent_id= -1;
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public int getParent_id() {
      return parent_id;
   }
   public void setParent_id(int parent_id) {
      this.parent_id = parent_id;
   }
}


Code of the Parent Object
Code:
package entities;

import java.util.Set;

public class Parent {
   private String name = null;
   private int id;
   private Set children = null;
   public Set getChildren() {
      return children;
   }
   public void setChildren(Set children) {
      this.children = children;
   }
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}


Code of the test class
Code:
          
package test;

import java.util.HashSet;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import entities.Child;
import entities.Parent;

public class TestParentChild {

   public static void main(String[] args) {
      try {
          SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
          Session session =sessionFactory.openSession();

          session.getTransaction().begin();
         Parent p= new Parent();
         p.setName("mom");

         Child c = new Child();
         c.setName("kid1");
         p.setChildren(new HashSet());
         p.getChildren().add(c);
         session.save(p);
         session.getTransaction().commit();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

}


Full stack trace of exception that occurs
Apr 23, 2008 4:13:28 PM org.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 1452, SQLState: 23000
Apr 23, 2008 4:13:28 PM org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: Cannot add or update a child row: a foreign key constraint fails (`hibernatetutorial/child`, CONSTRAINT `FK5A3F51C19D5F867` FOREIGN KEY (`PARENT_ID`) REFERENCES `parent` (`ID`))
Apr 23, 2008 4:13:28 PM org.hibernate.event.def.AbstractFlushingEventListener performExecutions
SEVERE: Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:139)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at test.TestParentChild.main(TestParentChild.java:28)
Caused by: java.sql.BatchUpdateException: Cannot add or update a child row: a foreign key constraint fails (`hibernatetutorial/child`, CONSTRAINT `FK5A3F51C19D5F867` FOREIGN KEY (`PARENT_ID`) REFERENCES `parent` (`ID`))
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1237)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:936)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 8 more
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:139)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at test.TestParentChild.main(TestParentChild.java:28)
Caused by: java.sql.BatchUpdateException: Cannot add or update a child row: a foreign key constraint fails (`hibernatetutorial/child`, CONSTRAINT `FK5A3F51C19D5F867` FOREIGN KEY (`PARENT_ID`) REFERENCES `parent` (`ID`))
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1237)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:936)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 8 more

Any thoughts from experts out there? Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 23, 2008 6:20 pm 
Beginner
Beginner

Joined: Tue Feb 26, 2008 2:04 pm
Posts: 28
Location: UK
Hi,

you can add a Parent property in your child entity and map that with a many-to-one relationship. Then when you create a child entity you simply set its parent. When you save save the child will be saved along with parent_id. Also, since your application cannot accept nulls as foreign keys you might want to add a not-null constraint like :

<key column="parent_id" not-null="true" />

_________________
savakos


Top
 Profile  
 
 Post subject: Still problem persists
PostPosted: Wed Apr 23, 2008 6:50 pm 
Newbie

Joined: Fri Mar 21, 2008 12:32 pm
Posts: 9
Thank you Mosa for the reply. When I do the following in the child.hbm.xml, the change made as indicated by you is in the <many-to-one> tag, everything else in the project stays the same, I get strange exception.

Code:
<hibernate-mapping>
   <class name="entities.Child" table="child">
      <id name="id" column="id" type="int" >
         <generator class="increment"/>
      </id>
      <property name="name" />
      <many-to-one name="parent_id" class="entities.Parent" property-ref="id"/>
   </class>
</hibernate-mapping>


EXCEPTION
Quote:
INFO: schema update complete
Hibernate: select max(id) from parent
Hibernate: select max(id) from child
Apr 23, 2008 6:46:32 PM org.hibernate.property.BasicPropertyAccessor$BasicGetter get
SEVERE: IllegalArgumentException in class: entities.Parent, getter method of property: id
org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of entities.Parent.id
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:171)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:183)
at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:3589)
at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:3305)
at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:181)
at org.hibernate.engine.ForeignKeys$Nullifier.isNullifiable(ForeignKeys.java:137)
at org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:69)
at org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:47)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.engine.CascadingAction$1.cascade(CascadingAction.java:218)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:334)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
Caused by: java.lang.IllegalArgumentException
at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:145)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:183)
at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:3589)
at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:3305)
at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:181)
at org.hibernate.engine.ForeignKeys$Nullifier.isNullifiable(ForeignKeys.java:137)
at org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:69)
at org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:47)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.engine.CascadingAction$1.cascade(CascadingAction.java:218)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:334)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 24, 2008 3:36 am 
Regular
Regular

Joined: Mon Aug 06, 2007 10:49 am
Posts: 67
Location: Banska Bystrica, Slovakia
i suppose that here <many-to-one name="parent_id" class="entities.Parent" property-ref="id"/> u should specify column in db not property-ref


Top
 Profile  
 
 Post subject: suggestion
PostPosted: Thu Apr 24, 2008 4:16 am 
Senior
Senior

Joined: Sun Jun 11, 2006 10:41 am
Posts: 164
Your child entity uses an integer to reference the parent. If you use a Parent class to reference the parent, and have the test code do something like: child.setParent(p), it should solve the problem. If you still want the child to have a getParent_id method, make sure it picks up the id like so: return getParent().getId().

example:
class Child {
..
//this will be the many-to-one target:
Parent getParent() { return this.parent;}
void setParent(Parent p) { this.parent = p; }

// this property will not be mapped to the db
int getParent_id() { return this.parent.getId(); }

Look up the one-to-many examples in the hibernate docs.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 24, 2008 5:03 am 
Beginner
Beginner

Joined: Tue Feb 26, 2008 2:04 pm
Posts: 28
Location: UK
probably you need to specify something like:

<many-to-one name="parent"
class="entities.Parent"
column="parent_id"
outer-join="false"
cascade="none"/>

the problem is, I think, that you are trying to map parent's id and not the property referencing your parent class.

_________________
savakos


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