-->
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.  [ 5 posts ] 
Author Message
 Post subject: help: PropertyValueException not-null property references...
PostPosted: Fri Aug 19, 2005 4:25 pm 
Expert
Expert

Joined: Wed Apr 06, 2005 5:03 pm
Posts: 273
Location: Salt Lake City, Utah, USA
Hibernate version:3.0.5


Hi, I'm having a problem with cascades on a <many-to-one>. I know that in the docs it says that

Quote:
It doesn't usually make sense to enable cascade on a <many-to-one> or <many-to-many> association.

but this is a unique many-to-one - i.e. a one-to-one - so I think I'm not doing anything too off-the-wall.

I have a 'base' class OneToOneBase and a 'sub' class OneToOneSub, that isn't really a subclass, but has a one-to-one relation to the base class. The reason I don't actually subclass is because OneToOneBase has a String PK (UUID), and OneToOneSub needs a Long (numeric) PK. So I set up this relationship, and then I created a kind of a facade class (OneToOneSubBO) that makes it look like OneToOneSub actually subclasses OneToOneBase.

Here is part of my OneToOneSubBO, to give you an idea:
Code:
public class OneToOneSubBO {

   private OneToOneSub mDO;

   public OneToOneSubBO(String pName, String pSomeString) {
      mDO = new OneToOneSub();
      OneToOneBase base = new OneToOneBase();
      mDO.setOneToOneBase(base);
      base.setName(pName);
      mDO.setSomeString(pSomeString);
   }

   public String getName() {
      return mDO.getOneToOneBase().getName();
   }
   
   public String getSomeString() {
      return mDO.getSomeString();
   }

   public void save(Session pSession) {
      pSession.saveOrUpdate(mDO);
   }
...


When I run the code below, saving the OneToOneSub should trigger a save of the OneToOneBase, but I get a PropertyValueException saying that OneToOneBase is null or transient. It is indeed transient, but shouldn't be because I specify cascade="all" on the relation.

If I make the small modification of changing the OneToOneBase Id to be Long, generator="native", everything works perfectly. With a custom generated String Id, the cascade part doesn't work. In the debug output, I see that it knows it needs to cascade to the OneToOneBase, generates a UUID for the OneToOneBase instance, says it's saving it, but never runs the SQL. With a Long "native" Id, the output is similar, but the SQL runs like it should!

Seems like a bug, but I know how often 'bugs' are mis-use, so I'm posting here to see if anyone can help. Thanks!

Mapping documents:

'Base' class:

Code:
<class
      name="com.nathan.hibernatetest.OneToOneBase"
      table="onetoonebase"
      schema="nathan">

      <id
         name="OneToOneBaseUuid"
         column="onetoonebase_uuid"
         type="java.lang.String"
         length="36">
         <generator
            class="com.nathan.hibernatetest.HibernateUuidGenerator" />
      </id>

      <property
         name="Name"
         type="java.lang.String"
         column="name"
         not-null="true"
         length="32" />

   </class>


'Sub' class:

Code:
<class
      name="com.nathan.hibernatetest.OneToOneSub"
      table="onetoonesub"
      schema="nathan">

      <id
         name="OneToOneSubId"
         column="onetoonesub_id"
         type="java.lang.Long">
         <generator class="native" />
      </id>

      <many-to-one
         name="OneToOneBase"
         class="com.nathan.hibernatetest.OneToOneBase"
         unique="true"
         cascade="all">
         <column
            name="onetoonebase_id"
            not-null="true"
            unique="true" />
      </many-to-one>

      <property
         name="SomeString"
         type="java.lang.String"
         column="somestring"
         not-null="false"
         length="128" />

   </class>


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

Code:
      Transaction t = s.beginTransaction();
      OneToOneSubBO subclass = new OneToOneSubBO("name", "somestring");
      try {
         subclass.save(s);
         t.commit();
      } catch (Exception e) {
         e.printStackTrace();
         throw e;
      }


Full stack trace of any exception that occurs:

Quote:
org.hibernate.PropertyValueException: not-null property references a null or transient value: com.nathan.hibernatetest.OneToOneSub.OneToOneBase
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:262)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:164)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101)
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:71)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:475)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:470)
at com.nathan.hibernatetest.OneToOneSubBO.save(OneToOneSubBO.java:40)
at OneToOneSubTest.testOne(OneToOneSubTest.java:86)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)


The generated SQL (show_sql=true):

None. This is the problem.

Debug level Hibernate log excerpt:

Quote:
3484 DEBUG [main] impl.SessionImpl - opened session at timestamp: 4605873859059712
3484 DEBUG [main] transaction.JDBCTransaction - begin
3484 DEBUG [main] jdbc.ConnectionManager - opening JDBC connection
3484 DEBUG [main] transaction.JDBCTransaction - current autocommit status: false
3500 DEBUG [main] def.AbstractSaveEventListener - transient instance of: com.nathan.hibernatetest.OneToOneSub
3500 DEBUG [main] def.DefaultSaveOrUpdateEventListener - saving transient instance
3500 DEBUG [main] def.AbstractSaveEventListener - saving [com.nathan.hibernatetest.OneToOneSub#<null>]
3500 DEBUG [main] def.AbstractSaveEventListener - executing insertions
3516 DEBUG [main] engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneSub
3516 DEBUG [main] engine.CascadingAction - cascading to saveOrUpdate: com.nathan.hibernatetest.OneToOneBase
3516 DEBUG [main] def.AbstractSaveEventListener - transient instance of: com.nathan.hibernatetest.OneToOneBase
3516 DEBUG [main] def.DefaultSaveOrUpdateEventListener - saving transient instance
3766 DEBUG [main] def.AbstractSaveEventListener - generated identifier: c84a3c41-10ee-11da-aa35-0f51324f0550, using strategy: com.nathan.hibernatetest.HibernateUuidGenerator
3766 DEBUG [main] def.AbstractSaveEventListener - saving [com.nathan.hibernatetest.OneToOneBase#c84a3c41-10ee-11da-aa35-0f51324f0550]
3781 DEBUG [main] engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneSub
[/code]


Top
 Profile  
 
 Post subject: Re: help: PropertyValueException not-null property reference
PostPosted: Fri Aug 19, 2005 4:44 pm 
Expert
Expert

Joined: Mon Feb 14, 2005 12:32 pm
Posts: 609
Location: Atlanta, GA - USA
Your mapping for OneToOneSub contains the following

Code:
<many-to-one
         name="OneToOneBase"
         class="com.nathan.hibernatetest.OneToOneBase"
         unique="true"
         cascade="all">
         <column
            name="onetoonebase_id"
            not-null="true"
            unique="true" />
</many-to-one>


which specifically says non-null="true"

So, you can either remove this restriction, or populate that field before trying to save your object.

Code:
      Transaction t = s.beginTransaction();
      OneToOneSubBO subclass = new OneToOneSubBO("name", "somestring");
      subclass.setOneToOneBase(oneToOneBaseObj);
      try {
         subclass.save(s);
         t.commit();
      } catch (Exception e) {
         e.printStackTrace();
         throw e;
      }

_________________
Preston

Please don't forget to give credit if/when you get helpful information.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 19, 2005 4:53 pm 
Expert
Expert

Joined: Wed Apr 06, 2005 5:03 pm
Posts: 273
Location: Salt Lake City, Utah, USA
Thanks for the reply. I do set OneToOneBase, in the OneToOneSubBO constructor:

Code:
public OneToOneSubBO(String pName, String pSomeString) {
      mDO = new OneToOneSub();
      OneToOneBase base = new OneToOneBase();
      mDO.setOneToOneBase(base);
      base.setName(pName);
      mDO.setSomeString(pSomeString);
   }


If you look at the debug output I posted, you'll see that Hibernate realizes it needs to save the OneToOneBase, even generates the OneToOneBase UUID PK value, but just doesn't finish with the insert statement! This exact same code works fine (executes the insert statement) if I don't use a String custom generated PK (I tried a "native" generated Long PK), so I believe it has to be related to the Id generator. Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 11:31 am 
Expert
Expert

Joined: Wed Apr 06, 2005 5:03 pm
Posts: 273
Location: Salt Lake City, Utah, USA
OK, I have simplified my code and mapping files down to the bare minimum to reproduce the problem. I also tried running on PostgreSQL as well as SQL Server. It turns out that the exception DOESN'T occur on PostgreSQL, but DOES on SQL Server. Here are my simplified mapping files:

Code:
<class
      name="com.nathan.hibernatetest.UUIDTable"
      table="uuidtable"
      schema="nathan">

      <id
         name="UUIDTable_UUID"
         column="uuidtable_uuid"
         type="java.lang.String"
         length="36">
         <generator
            class="com.nathan.hibernatetest.HibernateUuidGenerator" />
      </id>

   </class>

<class
      name="com.nathan.hibernatetest.OneToOneTable"
      table="onetoonetable"
      schema="nathan">

      <id
         name="OneToOneTableId"
         column="onetoonetable_id"
         type="java.lang.Long">
         <generator class="native" />
      </id>

      <many-to-one
         name="UUIDTable"
         class="com.nathan.hibernatetest.UUIDTable"
         unique="true"
         cascade="all">
         <column
            name="uuidtable_uuid"
            not-null="true"
            unique="true" />
      </many-to-one>

   </class>


Here is the code I am running:

Code:
      try {
         Session s = sf.openSession();
         Transaction t = s.beginTransaction();
         
         OneToOneTable onetooneclass = new OneToOneTable();
         UUIDTable uuidclass = new UUIDTable();
         onetooneclass.setUUIDTable(uuidclass);
         
         s.save(onetooneclass);
         
         t.commit();
         s.close();
      } catch (Exception e) {
         e.printStackTrace();
         throw e;
      }


Here is what running on PostgreSQL produces in the log (SUCCESS):

Quote:
3897 DEBUG [main] impl.SessionImpl - opened session at timestamp: 4606868032831488
3912 DEBUG [main] transaction.JDBCTransaction - begin
3912 DEBUG [main] jdbc.ConnectionManager - opening JDBC connection
3912 DEBUG [main] transaction.JDBCTransaction - current autocommit status: false
3912 DEBUG [main] jdbc.JDBCContext - before transaction completion
3912 DEBUG [main] def.DefaultSaveOrUpdateEventListener - saving transient instance
3912 DEBUG [main] jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
3912 DEBUG [main] hibernate.SQL - select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
3912 DEBUG [main] jdbc.AbstractBatcher - preparing statement
3959 DEBUG [main] id.SequenceGenerator - Sequence identifier generated: 1
3959 DEBUG [main] jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
3959 DEBUG [main] jdbc.AbstractBatcher - closing statement
3959 DEBUG [main] def.AbstractSaveEventListener - generated identifier: 1, using strategy: org.hibernate.id.SequenceGenerator
3959 DEBUG [main] def.AbstractSaveEventListener - saving [com.nathan.hibernatetest.OneToOneTable#1]
3990 DEBUG [main] engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneTable
3990 DEBUG [main] engine.CascadingAction - cascading to saveOrUpdate: com.nathan.hibernatetest.UUIDTable
3990 DEBUG [main] def.AbstractSaveEventListener - transient instance of: com.nathan.hibernatetest.UUIDTable
3990 DEBUG [main] def.DefaultSaveOrUpdateEventListener - saving transient instance
4240 DEBUG [main] def.AbstractSaveEventListener - generated identifier: 5e938180-131f-11da-9c03-7b6586cbaab8, using strategy: com.nathan.hibernatetest.HibernateUuidGenerator
4240 DEBUG [main] def.AbstractSaveEventListener - saving [com.nathan.hibernatetest.UUIDTable#5e938180-131f-11da-9c03-7b6586cbaab8]
4255 DEBUG [main] engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneTable
4255 DEBUG [main] engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneTable
4255 DEBUG [main] engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneTable
4255 DEBUG [main] transaction.JDBCTransaction - commit
4255 DEBUG [main] impl.SessionImpl - automatically flushing session
4255 DEBUG [main] def.AbstractFlushingEventListener - flushing session
4255 DEBUG [main] def.AbstractFlushingEventListener - processing flush-time cascades
4271 DEBUG [main] engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneTable
4271 DEBUG [main] engine.CascadingAction - cascading to saveOrUpdate: com.nathan.hibernatetest.UUIDTable
4271 DEBUG [main] def.AbstractSaveEventListener - persistent instance of: com.nathan.hibernatetest.UUIDTable
4271 DEBUG [main] def.DefaultSaveOrUpdateEventListener - ignoring persistent instance
4271 DEBUG [main] def.DefaultSaveOrUpdateEventListener - object already associated with session: [com.nathan.hibernatetest.UUIDTable#5e938180-131f-11da-9c03-7b6586cbaab8]
4271 DEBUG [main] engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneTable
4271 DEBUG [main] def.AbstractFlushingEventListener - dirty checking collections
4271 DEBUG [main] def.AbstractFlushingEventListener - Flushing entities and processing referenced collections
4271 DEBUG [main] def.AbstractFlushingEventListener - Processing unreferenced collections
4271 DEBUG [main] def.AbstractFlushingEventListener - Scheduling collection removes/(re)creates/updates
4271 DEBUG [main] def.AbstractFlushingEventListener - Flushed: 2 insertions, 0 updates, 0 deletions to 2 objects
4271 DEBUG [main] def.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
4271 DEBUG [main] pretty.Printer - listing entities:
4271 DEBUG [main] pretty.Printer - com.nathan.hibernatetest.UUIDTable{UUIDTable_UUID=5e938180-131f-11da-9c03-7b6586cbaab8}
4271 DEBUG [main] pretty.Printer - com.nathan.hibernatetest.OneToOneTable{OneToOneTableId=1, UUIDTable=com.nathan.hibernatetest.UUIDTable#5e938180-131f-11da-9c03-7b6586cbaab8}
4286 DEBUG [main] def.AbstractFlushingEventListener - executing flush
4286 DEBUG [main] entity.AbstractEntityPersister - Inserting entity: [com.nathan.hibernatetest.UUIDTable#5e938180-131f-11da-9c03-7b6586cbaab8]
4286 DEBUG [main] jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
4286 DEBUG [main] hibernate.SQL - insert into nathan.uuidtable (uuidtable_uuid) values (?)
Hibernate: insert into nathan.uuidtable (uuidtable_uuid) values (?)
4286 DEBUG [main] jdbc.AbstractBatcher - preparing statement
4286 DEBUG [main] entity.AbstractEntityPersister - Dehydrating entity: [com.nathan.hibernatetest.UUIDTable#5e938180-131f-11da-9c03-7b6586cbaab8]
4286 DEBUG [main] type.StringType - binding '5e938180-131f-11da-9c03-7b6586cbaab8' to parameter: 1
4286 DEBUG [main] jdbc.AbstractBatcher - Adding to batch
4286 DEBUG [main] entity.AbstractEntityPersister - Inserting entity: [com.nathan.hibernatetest.OneToOneTable#1]
4286 DEBUG [main] jdbc.AbstractBatcher - Executing batch size: 1
4302 DEBUG [main] jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
4302 DEBUG [main] jdbc.AbstractBatcher - closing statement
4302 DEBUG [main] jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
4302 DEBUG [main] hibernate.SQL - insert into nathan.onetoonetable (uuidtable_uuid, onetoonetable_id) values (?, ?)
Hibernate: insert into nathan.onetoonetable (uuidtable_uuid, onetoonetable_id) values (?, ?)
4318 DEBUG [main] jdbc.AbstractBatcher - preparing statement
4318 DEBUG [main] entity.AbstractEntityPersister - Dehydrating entity: [com.nathan.hibernatetest.OneToOneTable#1]
4318 DEBUG [main] type.StringType - binding '5e938180-131f-11da-9c03-7b6586cbaab8' to parameter: 1
4318 DEBUG [main] type.LongType - binding '1' to parameter: 2
4318 DEBUG [main] jdbc.AbstractBatcher - Adding to batch
4318 DEBUG [main] jdbc.AbstractBatcher - Executing batch size: 1
4333 DEBUG [main] jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
4333 DEBUG [main] jdbc.AbstractBatcher - closing statement
4333 DEBUG [main] def.AbstractFlushingEventListener - post flush
4333 DEBUG [main] jdbc.JDBCContext - before transaction completion
4333 DEBUG [main] impl.SessionImpl - before transaction completion
4349 DEBUG [main] transaction.JDBCTransaction - committed JDBC Connection
4349 DEBUG [main] jdbc.JDBCContext - after transaction completion
4349 DEBUG [main] impl.SessionImpl - after transaction completion
4349 DEBUG [main] impl.SessionImpl - closing session
4364 DEBUG [main] jdbc.ConnectionManager - closing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
4364 DEBUG [main] jdbc.JDBCContext - after transaction completion
4364 DEBUG [main] impl.SessionImpl - after transaction completion


Here is what running on SQL Server produces in the log (FAILURE):

Quote:
3648 DEBUG [main] impl.SessionImpl - opened session at timestamp: 4606870134833152
3648 DEBUG [main] transaction.JDBCTransaction - begin
3648 DEBUG [main] jdbc.ConnectionManager - opening JDBC connection
3648 DEBUG [main] transaction.JDBCTransaction - current autocommit status: false
3648 DEBUG [main] jdbc.JDBCContext - before transaction completion
3663 DEBUG [main] def.DefaultSaveOrUpdateEventListener - saving transient instance
3663 DEBUG [main] def.AbstractSaveEventListener - saving [com.nathan.hibernatetest.OneToOneTable#<null>]
3663 DEBUG [main] def.AbstractSaveEventListener - executing insertions
3663 DEBUG [main] engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneTable
3663 DEBUG [main] engine.CascadingAction - cascading to saveOrUpdate: com.nathan.hibernatetest.UUIDTable
3679 DEBUG [main] def.AbstractSaveEventListener - transient instance of: com.nathan.hibernatetest.UUIDTable
3679 DEBUG [main] def.DefaultSaveOrUpdateEventListener - saving transient instance
3912 DEBUG [main] def.AbstractSaveEventListener - generated identifier: 9079e6cc-1320-11da-bbbf-5d2f1a787932, using strategy: com.nathan.hibernatetest.HibernateUuidGenerator
3912 DEBUG [main] def.AbstractSaveEventListener - saving [com.nathan.hibernatetest.UUIDTable#9079e6cc-1320-11da-bbbf-5d2f1a787932]
3928 DEBUG [main] engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: com.nathan.hibernatetest.OneToOneTable
org.hibernate.PropertyValueException: not-null property references a null or transient value: com.nathan.hibernatetest.OneToOneTable.UUIDTable
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:167)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:516)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:506)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:502)
at UUIDTableTest.testOne(UUIDTableTest.java:90)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)


I am using Hibernate Tools to generate my java classes, and SchemaExport to generate my database tables. I ran all of this on the latest code (Hibernate 3.1 and Tools) from CVS.

Here are my classes:

OneToOneTable.java:
Code:
package com.nathan.hibernatetest;

import java.util.*;

/**
* OneToOneTable generated by hbm2java
*/
public class OneToOneTable  implements java.io.Serializable {

    // Fields   
     private Long OneToOneTableId;
     private UUIDTable UUIDTable;


    // Constructors
    /** default constructor */
    public OneToOneTable() {
    }
   
    /** constructor with id */
    public OneToOneTable(Long OneToOneTableId) {
        this.OneToOneTableId = OneToOneTableId;
    }

    // Property accessors
    /**
     *
     */
    public Long getOneToOneTableId() {
        return this.OneToOneTableId;
    }
   
    public void setOneToOneTableId(Long OneToOneTableId) {
        this.OneToOneTableId = OneToOneTableId;
    }

    /**
     *
     */
    public UUIDTable getUUIDTable() {
        return this.UUIDTable;
    }
   
    public void setUUIDTable(UUIDTable UUIDTable) {
        this.UUIDTable = UUIDTable;
    }
}


UUIDTable.java:

Code:
package com.nathan.hibernatetest;

import java.util.*;

/**
* UUIDTable generated by hbm2java
*/
public class UUIDTable  implements java.io.Serializable {

    // Fields   
     private String UUIDTable_UUID;

    // Constructors
    /** default constructor */
    public UUIDTable() {
    }
   
    /** constructor with id */
    public UUIDTable(String UUIDTable_UUID) {
        this.UUIDTable_UUID = UUIDTable_UUID;
    }

    // Property accessors
    /**
     *
     */
    public String getUUIDTable_UUID() {
        return this.UUIDTable_UUID;
    }
   
    public void setUUIDTable_UUID(String UUIDTable_UUID) {
        this.UUIDTable_UUID = UUIDTable_UUID;
    }
}


Here is the DDL for SQL Server:

Code:
create table nathan.onetoonetable (onetoonetable_id numeric(19,0) identity not null, uuidtable_uuid varchar(36) not null unique, primary key (onetoonetable_id));
create table nathan.uuidtable (uuidtable_uuid varchar(36) not null, primary key (uuidtable_uuid));
alter table nathan.onetoonetable add constraint FKEACC67899F4052C3 foreign key (uuidtable_uuid) references nathan.uuidtable;


And here is the DDL for PostgreSQL:

Code:
create table nathan.onetoonetable (onetoonetable_id int8 not null, uuidtable_uuid varchar(36) not null unique, primary key (onetoonetable_id));
create table nathan.uuidtable (uuidtable_uuid varchar(36) not null, primary key (uuidtable_uuid));
alter table nathan.onetoonetable add constraint FKEACC67899F4052C3 foreign key (uuidtable_uuid) references nathan.uuidtable;
create sequence hibernate_sequence;


I plan on submitting this to JIRA as a bug unless someone can point out my problem. Thanks in advance for any help!

Nathan


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 23, 2005 12:10 pm 
Expert
Expert

Joined: Wed Apr 06, 2005 5:03 pm
Posts: 273
Location: Salt Lake City, Utah, USA
I submitted a bug to JIRA (HHH-894), and Gavin rejected it within minutes, with no explanation why.

I've done more research, and I have an even more simplified setup that will reproduce the problem. Here are my mapping files:

Code:
<class
      name="com.nathan.hibernatetest.StringIdTable"
      table="stringidtable">

      <id
         name="StringIdTableId"
         column="stringidtable_id"
         type="java.lang.String"
         length="36">
         <generator class="assigned"/>
      </id>

   </class>

<class
      name="com.nathan.hibernatetest.OneToOneTable"
      table="onetoonetable">

      <id
         name="OneToOneTableId"
         column="onetoonetable_id"
         type="java.lang.Long">
         <generator class="native" />
      </id>

      <many-to-one
         name="StringIdTable"
         class="com.nathan.hibernatetest.StringIdTable"
         unique="true"
         cascade="all">
         <column
            name="stringidtable_id"
            not-null="true"
            unique="true" />
      </many-to-one>

   </class>


My POJOs are generated by Hibernate Tools, so nothing fancy. My schema is also generated by SchemaExport, so nothing fancy. I can post them if needed.

Here is the code that will cause the exception:

Code:
      try {
         Session s = sf.openSession();
         Transaction t = s.beginTransaction();
         
         OneToOneTable onetooneclass = new OneToOneTable();
         StringIdTable stringidclass = new StringIdTable();
         stringidclass.setStringIdTableId("somestringid");
         onetooneclass.setStringIdTable(stringidclass);
         
         s.save(onetooneclass);
         
         t.commit();
         s.close();
      } catch (Exception e) {
         e.printStackTrace();
         throw e;
      }


It has something to do with the "native" generator in OneToOneTable. It doesn't work if native translated to "identity", but works if it translates to "sequence".

In the Hibernate source, org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId, line 101:

return performSave(entity, null, persister, true, anything, source);

is executed for an identity id table, and line 114:

return performSave(entity, generatedId, persister, false, anything, source);

is executed for a sequence id table.

For some reason, if useIdentityColumn = true in performSave(...), it doesn't realize that my StringIdTable instance is already in the queue to be saved, and org.hibernate.engine.ForeignKeys$Nullifier says that OneToOneTable's reference to StringIdTable should be set to null. If OneToOneTable uses a sequence, it leaves it alone (doesn't set it to null).

Gavin or someone, can I get some help?? I don't understand why the identifier generator should affect nullability of cascasing values.

Thanks in advance.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.