-->
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: TransientObjectException from ForeignKeys
PostPosted: Fri Sep 29, 2006 1:19 pm 
Newbie

Joined: Fri Sep 29, 2006 12:42 pm
Posts: 4
First, let me say i've been using Hibernate for about 6 months now and really appreciate not having to write my own DB-access code. I'm writing because i came across something that surprised me. I have a work-around, but am curious why my first approach didn't work.

Summary:
Let there be 3 classes: A, B, C. Class A has a List of B. B has a reference to C. The B-C relationship is one-to-one and one-way (B knows C, but not vice versa). Class A is modeled in Hibernate as an entity object, as is C. (In the real code, the object represented by C is very complex and it would not be appropriate to model it as a value object.) My original approach had B as a value object, but this led to a T.O.E. when saving A. By making B an entity object, i no longer received the T.O.E. and A,B,C were persisted properly.


What follows is a phony example that parallels my real code enough to demonstrate the behavior.

Here is the mapping that works:
Code:
<hibernate-mapping package="toe">
   
   <class name="Foot">
      <id name="id" type="long" access="field">
         <generator class="native"/>
      </id>
            
      <property name="isLeft"     access="field"/>
      <property name="stinkLevel" access="field"/>
      
      <list name="toes" cascade="all-delete-orphan" access="field">
         <key   column="FOOT_ID"/>
         <index column="INDEX"/>
         
         <one-to-many class="Toe"/>
      </list>
   </class>
   
   
   <class name="Toe">
      <id name="id" type="long" access="field">
         <generator class="native"/>
      </id>

      <property name="name"        access="field"/>
      <property name="millimeters" access="field"/>

      <many-to-one name="nail"
            class="Nail"
            column="NAIL_ID"
            cascade="all"
            unique="true"
            access="field"/>
   </class>
   
   
   <class name="Nail">
      <id name="id" type="long" access="field">
         <generator class="native"/>
      </id>

      <property name="isPainted" access="field"/>
      <property name="color"     access="field"/>
   </class>
   
   
</hibernate-mapping>


Here is the mapping that causes a TransientObjectException:
Code:
<hibernate-mapping package="toe">
   
   <class name="Foot">
      <id name="id" type="long" access="field">
         <generator class="native"/>
      </id>
            
      <property name="isLeft"     access="field"/>
      <property name="stinkLevel" access="field"/>
      
      <list name="toes" access="field">
         <key   column="FOOT_ID"/>
         <index column="INDEX"/>
         
         <composite-element class="Toe">
            <property name="name"        access="field"/>
            <property name="millimeters" access="field"/>
            <many-to-one name="nail"
                  class="Nail"
                  column="NAIL_ID"
                  cascade="all"
                  unique="true"
                  access="field"/>
         </composite-element>
      </list>
   </class>
   
   <class name="Nail">
      <id name="id" type="long" access="field">
         <generator class="native"/>
      </id>

      <property name="isPainted" access="field"/>
      <property name="color"     access="field"/>
   </class>
   
</hibernate-mapping>


This is the java code that corresponds to the above xml:
Code:
package toe;

import java.util.ArrayList;
import java.util.List;

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

/**
* This is like SwitchingScan in our real application.
* <p>
* The purpose of this class is to demonstrate that mapping class Toe
* as a value object in Hibernate gives a TransientObjectException,
* while mapping it as a entity object does not.  In both situations
* class Nail is mapped as an entity object and there is a one-way
* (from Toe to Nail), one-to-one, relationship between Toe and Nail.</p>
*/
public class Foot
{
  long      id = -1L;
  boolean   isLeft;
  int       stinkLevel;
  List<Toe> toes = new ArrayList<Toe>();
 
  public static void main(String[] args)
  {
    Foot leftFoot = new Foot();
   
    leftFoot.isLeft     = true;
    leftFoot.stinkLevel = 7;
   
    String[] names  = {"Porky", "Petunia", "Ms. Piggy", "Zaentz", "Little Piggy"};
    String[] colors = {"Red", "White", "Blue", "Purple", "Black"};
    double size = 40.0;
    for (int t=0; t < 5; t++)
    {
      Nail nail      = new Nail();
      nail.isPainted = true;
      nail.color     = colors[t];
     
      Toe toe         = new Toe();
      toe.name        = names[t];
      toe.millimeters = size;
      toe.nail        = nail;
     
      leftFoot.toes.add(toe);
     
      size -= 5.0;
    }
   
    Dao dao = new Dao();
    dao.save(leftFoot);
    dao.close();
  }
}


/** This is like SwitchSetting in our real application. */
class Toe
{
  //id is here only because crafting Toe as a value object didn't work as hoped
  long   id = -1L;
 
  String name;
  double millimeters;
  Nail   nail;
}


/** This is like Source in our real application. */
class Nail
{
  long    id = -1L;
  boolean isPainted;
  String  color;
}




class Dao
{
  private SessionFactory sessionFactory;
 
  private SessionFactory getSessionFactory()
  {
    if (sessionFactory == null)
    {
      try
      {
        Configuration conf = new Configuration();
        conf.configure("Feet.cfg.xml");
       
        sessionFactory = conf.buildSessionFactory();
      }
      catch (HibernateException ex)
      {
        System.out.println("Problem getting SessionFactory.");
        ex.printStackTrace();
        System.exit(-1);
      }
    }
   
    return sessionFactory;
  }
 
  void save(Foot foot)
  {
    Session session = getSessionFactory().openSession();
    Transaction tran = null;
   
    try
    {
      tran = session.beginTransaction();

      session.saveOrUpdate(foot);
     
      tran.commit();
    }
    catch (Exception ex)
    {
      if (tran != null)
        tran.rollback();
      System.out.println("Problem saving Foot.");
      ex.printStackTrace();
      System.exit(-1);
    }
    finally
    {
      session.close();
    }
  }
 
  void close()
  {
    getSessionFactory().close();
  }
}


Top
 Profile  
 
 Post subject: Any workaround for this
PostPosted: Sat Oct 20, 2007 11:58 pm 
Newbie

Joined: Sat Oct 20, 2007 11:55 pm
Posts: 1
I am having the exact same problem with hibernate 3.2
Any suggestions for a fix or workaround ?
Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 22, 2007 10:27 am 
Newbie

Joined: Fri Sep 29, 2006 12:42 pm
Posts: 4
The work-around i used is demonstrated in the original post. I originally tried to use a Hibernate mapping like the 2nd one shown above, where "Toe" is defined as a composite-element inside "Foot". The work-around is shown in the 1st mapping, above, where "Toe" is now its own entity class.


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.