[hibernate-issues] [Hibernate-JIRA] Updated: (HHH-3544) Nullability.checkNullability() throws PropertyValueException (not-null property references a null property) for a property that ForeignKeys.Nullifier.nullifyTransientReferences() just nulled

Krasimir Chobantonov (JIRA) noreply at atlassian.com
Thu Dec 4 18:13:17 EST 2008


     [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-3544?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Krasimir Chobantonov updated HHH-3544:
--------------------------------------

    Attachment: 3.3.1.GA-HHH-3544

This patch fixes the problem but can be improved so that if it detect dependencies between the object in the graph that is about to be saved then to nullify only the nullable foreign key relationships and add an update action to establish the relation after the insert.

Currently the patch does not do that - it will order all possible dependencies in the correct order but it will not try to solve cyclic object dependency by trying to nullifiy the nullable relationships and add an update action to fix the relationship after the insert.

The original problem indeed is because Hibernate will nullify all references to entities that are having status of SAVING - meaning those object are going to be inserted in the dababase but their insert action is not yet scheduled.

Jeppe, would you mind to try to patch and see if it will fix your problem as well ? Of course the bugfix needs to be reviewed by the Hibernate team member (e.g. a person with more knowledge of the whole Hibernate code base)

Thanks
Krasimir

> Nullability.checkNullability() throws PropertyValueException (not-null property references a null property) for a property that ForeignKeys.Nullifier.nullifyTransientReferences() just nulled
> ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HHH-3544
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-3544
>             Project: Hibernate Core
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 3.3.1
>         Environment: Hibernate 3.3.1, Hibernate Annotations 3.4, Hibernate Commons-Annotation 3.3.1, Hibernate EntityManager 3.4, PostgreSQL 8.2.5, Java 5
>            Reporter: Jeppe Cramon
>         Attachments: 3.3.1.GA-HHH-3544, HibernateNullabilityProblem.zip
>
>
> Nullability.checkNullability throws PropertyValueException (not-null property references a null property) for a property that  ForeignKeys.Nullifier.nullifyTransientReferences just nulled.
> I've included an Eclipse Java project which can reproduce the problem (didn't include the jars). 
> The problem requires a pretty big graph to be reproduce able. The file "Domain Model.jpg" displays the Classes that take part in the problem.
> The Domain Model is a simplification of the entities from our application.
> In the example, ModelTest.java, there's only one active instance entity of each type (from A to H).
> With the given test case, when an instance of a is passed to entityManager.persist(..), then the following exception is thrown:
> javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: dk.hibernatetest.model.C.b
> 	at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
> 	at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:226)
> 	at dk.hibernatetest.model.ModelTest.test(ModelTest.java:49)
> 	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:585)
> 	at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
> 	at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
> 	at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
> 	at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
> 	at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
> 	at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66)
> 	at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
> 	at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
> 	at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
> 	at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
> 	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
> 	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
> 	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
> 	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
> 	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
> 	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
> Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: dk.hibernatetest.model.C.b
> 	at org.hibernate.engine.Nullability.checkNullability(Nullability.java:95)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
> 	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
> 	at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
> 	at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
> 	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
> 	at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:636)
> 	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:628)
> 	at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:28)
> 	at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
> 	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
> 	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
> 	at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:319)
> 	at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:265)
> 	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:242)
> 	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
> 	at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
> 	at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:479)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:357)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
> 	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
> 	at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
> 	at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
> 	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
> 	at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:636)
> 	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:628)
> 	at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:28)
> 	at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
> 	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
> 	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
> 	at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
> 	at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:454)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
> 	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
> 	at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
> 	at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
> 	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
> 	at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:636)
> 	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:628)
> 	at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:28)
> 	at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
> 	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
> 	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
> 	at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
> 	at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:454)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
> 	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
> 	at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
> 	at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
> 	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
> 	at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:636)
> 	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:628)
> 	at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:28)
> 	at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
> 	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
> 	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
> 	at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
> 	at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:454)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
> 	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
> 	at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
> 	at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
> 	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
> 	at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:636)
> 	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:628)
> 	at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:28)
> 	at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
> 	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
> 	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
> 	at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:319)
> 	at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:265)
> 	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:242)
> 	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
> 	at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
> 	at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:479)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:357)
> 	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
> 	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
> 	at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
> 	at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
> 	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
> 	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
> 	at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:645)
> 	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:619)
> 	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:623)
> 	at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:220)
> 	... 21 more
> As noted in TestModel.java, if some of the other entities (namely c, g or h) are passed to persist(), then the problem doesn't occur.
> I've tried to debug the problem and the only difference I've seen inside ForeignKeys.Nullifier.nullifyTransientReferences() is that, in the cases where an exception is thrown, then the B instance that C.b points to has the state SAVING, whereas when the exception isn't thrown, then it has state MANAGED.
> When the B instance has state SAVING, then ForeignKeys.Nullifier.nullifyTransientReferences() nulls then entry in it's value array.
> After that, Nullability.checkNullability(), performs a null check, which fails because ForeignKeys.Nullifier.nullifyTransientReferences() just nulled the property in the values array.
> Could it be a solution to reverse the order of the ForeignKeys.Nullifier.nullifyTransientReferences()  and  Nullability.checkNullability()  (See AbstractEventListener.performSaveOrReplicate(...)) 
> or does ForeignKeys.Nullifier.nullifyTransientReferences() instead have to take nullability into considerations?
> /Jeppe

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        



More information about the hibernate-issues mailing list