-->
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.  [ 8 posts ] 
Author Message
 Post subject: Why check for transient references during Session.save()?
PostPosted: Sat Aug 20, 2005 10:33 pm 
Regular
Regular

Joined: Wed May 11, 2005 11:57 pm
Posts: 80
It seems strange to me that Hibernate checks for null / persistent required references during Session.save(). Wouldn't Session.flush() be a much better time to do this?

The problem that I'm running into is that the order in which I call save becomes very prone to break when I have required object references. For example, assume that A has a required relationship to B. This code:

Code:
A = new TypeA();
B = new TypeB();
...
session.save(A);
session.save(B);
myTransaction.commit()

fails with a "not-null property references a null or transient value" exception before it even gets to committing the transaction. Saving B first will solve the problem, or I can configure cascading saves from A to B, but if B also has a required reference back to A, then cascading is the only solution. It would be so much nicer if Hibernate waited until session.flush() to check for those references - that would be a much less 'fragile' solution.

Is there a technical or logical reason that Hibernate cannot work this way? Is this worth submitting a Jira issue for?

Hibernate version: 3.05


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 20, 2005 10:51 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
You must be using identity pk generation, in which case inserts happen immediately.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Aug 21, 2005 12:07 am 
Regular
Regular

Joined: Wed May 11, 2005 11:57 pm
Posts: 80
gavin wrote:
You must be using identity pk generation, in which case inserts happen immediately.


Thanks for your fast and helpful response - I will experiment with the hilo and guid pk generation (I'm using MySQL) - these will solve my problem?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 26, 2005 6:20 pm 
Regular
Regular

Joined: Wed May 11, 2005 11:57 pm
Posts: 80
gavin wrote:
You must be using identity pk generation, in which case inserts happen immediately.


I changed all of entities to use HiLo generation instead of native, but I'm still getting the same exception:


org.hibernate.PropertyValueException: not-null property references a null or transient value: com.prosc.test.Classroom.campus
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:236)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:160)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:481)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:476)
at com.prosc.test.SaveOrderTest.testSavingOrder(SaveOrderTest.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:31)

Here is the code which fails:
Code:
Session session = TestUtils.sessionFactory.openSession();
      Transaction tx = session.beginTransaction();

      Classroom room = new Classroom();
      Campus campus = new Campus();
      room.setCampus(campus);

      session.save(room); //This fails, since the campus has not been saved yet
      session.save(campus);

      tx.commit();
      session.close();


Here are the relevant mapping files:
Code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.prosc.test" default-cascade="lock" default-access="field">
   <class lazy="false" name="Classroom">
      <id name="id" type="java.lang.Long" unsaved-value="null">
         <generator class="hilo">
            <param name="table">Id_Classroom</param>
         </generator>
      </id>
      <property name="roomNumber" type="java.lang.String"/>
      <property name="seatingCapacity" type="java.lang.String"/>
      <many-to-one name="campus" column="campusId" not-null="true"/>
      <list name="courses" lazy="true" inverse="false">
         <key column="classroomId"/>
         <index column="sortOrderForclassroom"/>
         <one-to-many class="Course"/>
      </list>
   </class>
</hibernate-mapping>

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.prosc.test" default-cascade="lock" default-access="field">
   <class lazy="false" name="Campus">
      <id name="id" type="java.lang.Long" unsaved-value="null">
         <generator class="hilo">
            <param name="table">Id_Campus</param>
         </generator>
      </id>
      <property name="city" type="java.lang.String"/>
      <property name="state" type="java.lang.String"/>
   </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Sun Aug 28, 2005 1:14 am 
Regular
Regular

Joined: Wed May 11, 2005 11:57 pm
Posts: 80
What is the expected behavior for transient property checking during save? Is this documented anywhere? The current behavior I'm seeing (where transient references case save to fail) is forcing me to set cascading saves in many places that are not really appropriate.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 26, 2005 3:37 pm 
Regular
Regular

Joined: Wed May 11, 2005 11:57 pm
Posts: 80
gavin wrote:
You must be using identity pk generation, in which case inserts happen immediately.


I've tried using guid and hilo as id generators, and the test still fails. Is there a solution to this? Should I file this as a bug?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 26, 2005 4:17 pm 
Expert
Expert

Joined: Mon Feb 14, 2005 12:32 pm
Posts: 609
Location: Atlanta, GA - USA
jbarnum wrote:

...
It seems strange to me that Hibernate checks for null / persistent required references during Session.save(). Wouldn't Session.flush() be a much better time to do this?
...

Code:
Session session = TestUtils.sessionFactory.openSession();
      Transaction tx = session.beginTransaction();

      Classroom room = new Classroom();
      Campus campus = new Campus();
      room.setCampus(campus);

      session.save(room); //This fails, since the campus has not been saved yet
      session.save(campus);

      tx.commit();
      session.close();



Wouldn't this code fail even if this check was done in the flush() since it would still validate the room first, then the campus ?

And if id didn't fail in the Hibernate code, then surely during the DB insert if the FK to Campus is not nullable and the Room is saved first.

_________________
Preston

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


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 26, 2005 8:42 pm 
Regular
Regular

Joined: Wed May 11, 2005 11:57 pm
Posts: 80
pksiv wrote:
Wouldn't this code fail even if this check was done in the flush() since it would still validate the room first, then the campus ?

And if id didn't fail in the Hibernate code, then surely during the DB insert if the FK to Campus is not nullable and the Room is saved first.


If it waited until flush() to validate, then it would see that both instances are persistent, or at least will be as soon as the commit is done.

Regarding the DB complaining about a null FK, I thought that if I was using the HiLo or GUID ID generator, Hibernate would create the ID for me without having to first insert the record into the DB. Therefore, it would never have to insert a null FK.


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