-->
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.  [ 3 posts ] 
Author Message
 Post subject: Schema creation - Parent with child and bag<child> dat
PostPosted: Sat Nov 25, 2006 7:00 pm 
Newbie

Joined: Sat Nov 25, 2006 2:56 pm
Posts: 11
Update: Ooops

I was having trouble even coming up with a workaround when I tripped across why -

Code:
<bag name="listOfChildren" table="list_of_children" cascade="all-delete-orphan" lazy="true">
         <key column="[b]id[/b]"/>
         <one-to-many class="hibernatetest.Child"/>
</bag>


Oops. I used the same name for the primary id column as I was using for the foreign key column, which obviously doesn't work.

It's my mistake. It would be nice if Hibernate would let me know about this overlapping-column-name kind of thing and show some sort of error, but it does turn out to be my fault.


I'm leaving my original post below.

----------------------------------------------------

I'm either really messing my mapping with some little thing, or SchemaUpdate is generating an invalid foreign key (I'm using hbm2ddl.auto=create in my hibernate mapping file).

I've distilled the problem into the code/mappings below to make it as simple as possible to look at.

In the code, I have a Parent class that holds a reference to a single Child object (oneChild), and also has a Bag of Child objects (listOfChildren). The parent creates a Child object and assigns it to the oneChild property. Then it grabs that Child object, sets oneChild to null, and adds the Child object to the listOfChildren. Things still seem to be ok here.

Then it creates a second Child object and assigns it to oneChild. When the session is flushed, I get an exception saying that a foreign key constraint fails.

I looked into the constraint, and this is the constraint that's causing the problem:

Code:
16:31:55,813 DEBUG SchemaExport:303 -
    alter table children
        add index FK62EA5DFFDD08DB2F (id),
        add constraint FK62EA5DFFDD08DB2F
        foreign key (id)
        references parents (id)


Apparently, it's hooking up a foreign key between children.id and parents.id. This seems wrong to me - I don't think the id column in the children table is supposed to be mapped as being both the primary key for the children table and a foreign key that refers to the primary key of the parent table.

Is this some sort of error in my mapping, or is it a schema generation bug?





Data Classes Code:
Code:
package hibernatetest;

import java.util.*;

public class Parent {
   private long id;
   private Child oneChild = null;
   private List<Child> listOfChildren = new ArrayList();
   
   public Parent() {
   }

   public long getId() {
      return id;
   }

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

   public List<Child> getListOfChildren() {
      return listOfChildren;
   }

   private void setListOfChildren(List<Child> listOfChildren) {
      this.listOfChildren = listOfChildren;
   }

   public Child getOneChild() {
      return oneChild;
   }

   public void setOneChild(Child oneChild) {
      this.oneChild = oneChild;
   }
}


Code:
package hibernatetest;

import java.util.*;

public class Child {
   private long id;
   private Parent parent;
   
   protected Child() {}
   
   public Child(Parent parent) {
      this.setParent(parent);
   }

   public long getId() {
      return id;
   }

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

   public Parent getParent() {
      return parent;
   }

   public void setParent(Parent parent) {
      this.parent = parent;
   }
}



Hibernate version:
3.2.1

Mapping documents:

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

<hibernate-mapping>
    <class name="hibernatetest.Parent" table="parents">
        <id name="id">
            <generator class="native"/>
        </id>
      
      <many-to-one name="oneChild" cascade="all" />
      
      <bag name="listOfChildren" table="list_of_children" cascade="all-delete-orphan" lazy="true">
         <key column="id"/>
         <one-to-many class="hibernatetest.Child"/>
      </bag>
    </class>
</hibernate-mapping>


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

<hibernate-mapping>
    <class name="hibernatetest.Child" table="children">
        <id name="id">
            <generator class="native"/>
        </id>
      
      <many-to-one name="parent" column="parent_id"/>
    </class>
</hibernate-mapping>


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

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost/testhibernate</property>
        <property name="connection.username">testhibernate</property>
        <property name="connection.password"></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
      <property name="format_sql">true</property>
      <property name="hibernate.use_sql_comments">true</property>
      
      <!-- Drop and re-create the database schema on startup -->
      <property name="hbm2ddl.auto">create</property> <!-- create-drop -->
      
      <!-- List of the persistant classes -->
      <mapping resource="hibernatetest/Parent.hbm.xml"/>
      <mapping resource="hibernatetest/Child.hbm.xml"/>

    </session-factory>

</hibernate-configuration>


Code between sessionFactory.openSession() and session.close():

Code:
package hibernatetest;

import org.hibernate.*;
import org.hibernate.cfg.*;

public class Main {
   public static void main(String[] args) throws Throwable {
      SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
      
      Session session = sessionFactory.openSession();
      Transaction transaction = session.beginTransaction();
      try {
         // Create the parent and set it's oneChild property
         Parent parent = new Parent();
         session.save(parent);
         parent.setOneChild(new Child(parent));
         
         // Move the oneChild object to the collection of Child objects
         Child child = parent.getOneChild();
         parent.setOneChild(null);
         parent.getListOfChildren().add(child);
         
         transaction.commit();
      } catch(Exception ex) {
         transaction.rollback();
         throw ex;
      } finally {
         session.close();
      }
      
      session = sessionFactory.openSession();
      transaction = session.beginTransaction();
      try {
         // Try to set another oneChild object on the parent - error occurs
         Parent parent = (Parent) session.load(Parent.class, new Long(1));
         parent.setOneChild(new Child(parent));
         
         transaction.commit();
      } catch(Exception ex) {
         transaction.rollback();
         throw ex;
      } finally {
         session.close();
      }
   }
}



Full stack trace of any exception that occurs:

Code:
16:31:56,795  WARN JDBCExceptionReporter:77 - SQL Error: 1452, SQLState: 23000
16:31:56,885 ERROR JDBCExceptionReporter:78 - Cannot add or update a child row: a foreign key constraint fails (`testhibernate/children`, CONSTRAINT `FK62EA5DFFDD08DB2F` FOREIGN KEY (`id`) REFERENCES `parents` (`id`))
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not insert: [hibernatetest.Child]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:40)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2108)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2588)
        at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:48)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
        at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:290)
        at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
        at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:98)
        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.cascade(Cascade.java:130)
        at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:131)
        at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:122)
        at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:65)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
        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 hibernatetest.Main.main(Main.java:38)
Caused by: com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`testhibernate/children`, CONSTRAINT `FK62EA5DFFDD08DB2F` FOREIGN KEY (`id`) REFERENCES `parents` (`id`))
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)
        at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1169)
        at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:693)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1404)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1318)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1303)
        at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:73)
        at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:33)
        ... 26 more
Java Result: 1



Name and version of the database you are using:
MySQL 5.0.22-community-max-nt

The generated SQL (show_sql=true):

Code:
16:31:54,161 DEBUG SchemaExport:303 -
    alter table children
        drop
        foreign key FK62EA5DFF586F7EE4
16:31:54,521 DEBUG SchemaExport:303 -
    alter table children
        drop
        foreign key FK62EA5DFFDD08DB2F
16:31:54,852 DEBUG SchemaExport:303 -
    alter table parents
        drop
        foreign key FKD0B60D0954B030E8
16:31:55,192 DEBUG SchemaExport:303 -
    drop table if exists children
16:31:55,242 DEBUG SchemaExport:303 -
    drop table if exists parents
16:31:55,303 DEBUG SchemaExport:303 -
    create table children (
        id bigint not null auto_increment,
        parent_id bigint,
        primary key (id)
    ) ENGINE=InnoDB
16:31:55,423 DEBUG SchemaExport:303 -
    create table parents (
        id bigint not null auto_increment,
        oneChild bigint,
        primary key (id)
    ) ENGINE=InnoDB
16:31:55,523 DEBUG SchemaExport:303 -
    alter table children
        add index FK62EA5DFF586F7EE4 (parent_id),
        add constraint FK62EA5DFF586F7EE4
        foreign key (parent_id)
        references parents (id)
16:31:55,813 DEBUG SchemaExport:303 -
    alter table children
        add index FK62EA5DFFDD08DB2F (id),
        add constraint FK62EA5DFFDD08DB2F
        foreign key (id)
        references parents (id)
16:31:56,154 DEBUG SchemaExport:303 -
    alter table parents
        add index FKD0B60D0954B030E8 (oneChild),
        add constraint FKD0B60D0954B030E8
        foreign key (oneChild)
        references children (id)
16:31:56,474  INFO SchemaExport:196 - schema export complete
Hibernate:
    /* insert hibernatetest.Parent
        */ insert
        into
            parents
            (oneChild)
        values
            (?)
Hibernate:
    /* insert hibernatetest.Child
        */ insert
        into
            children
            (parent_id)
        values
            (?)
Hibernate:
    /* create one-to-many row hibernatetest.Parent.listOfChildren */ update
        children
    set
        id=?
    where
        id=?
Hibernate:
    /* load hibernatetest.Parent */ select
        parent0_.id as id0_0_,
        parent0_.oneChild as oneChild0_0_
    from
        parents parent0_
    where
        parent0_.id=?
Hibernate:
    /* insert hibernatetest.Child
        */ insert
        into
            children
            (parent_id)
        values
            (?)


Debug level Hibernate log excerpt:

See above stuff.


Last edited by PaulRivers on Mon Nov 27, 2006 2:37 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 27, 2006 2:25 am 
Senior
Senior

Joined: Sat Jul 17, 2004 5:16 pm
Posts: 143
Is there a question here, or is it just a rant? :)

If you had the id of one linked to the id of another, that is a one-to-one. Yes, not sure why you would have this in a bag structure, but flexibility is always good for something generic like Hibernate... you need to map things correctly.

Chris


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 27, 2006 2:40 am 
Newbie

Joined: Sat Nov 25, 2006 2:56 pm
Posts: 11
I originally was asking a question, then while trying to come up with a workaround I realized it was my fault and updated my post accordingly. I've updated it again to try to make it clearer - I just left it up because I thought someone else might find it amusing.


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