[hibernate-dev] HHH-13959 - OneToOne JoinTable with unique constraints work around?

Jason Pyeron jpyeron at pdinc.us
Mon Apr 20 03:54:25 EDT 2020


I applied the patch to b897a36f2f.

The only new test failure I encountered was org.hibernate.test.annotations.cascade.NonNullableCircularDependencyCascadeTest

testIdClassInSuperclass
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1356)
	at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1339)
	at org.hibernate.test.annotations.cascade.NonNullableCircularDependencyCascadeTest.testIdClassInSuperclass(NonNullableCircularDependencyCascadeTest.java:42)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.hibernate.testing.junit4.ExtendedFrameworkMethod.invokeExplosively(ExtendedFrameworkMethod.java:45)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)
	at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
	at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:109)
	at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3235)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3760)
	at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:107)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
	at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
	at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1352)
	... 17 more
Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "DEFAULTCHILDID"; SQL statement:
insert into Parent (defaultChildId, id) values (?, ?) [23502-196]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
	at org.h2.message.DbException.get(DbException.java:179)
	at org.h2.message.DbException.get(DbException.java:155)
	at org.h2.table.Column.validateConvertUpdateSequence(Column.java:345)
	at org.h2.table.Table.validateConvertUpdateSequence(Table.java:797)
	at org.h2.command.dml.Insert.insertRows(Insert.java:151)
	at org.h2.command.dml.Insert.update(Insert.java:114)
	at org.h2.command.CommandContainer.update(CommandContainer.java:101)
	at org.h2.command.Command.executeUpdate(Command.java:260)
	at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:164)
	at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:150)
	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
	... 28 more

> -----Original Message-----
> From: hibernate-dev-bounces at lists.jboss.org [mailto:hibernate-dev-bounces at lists.jboss.org]
> On Behalf Of Jason Pyeron
> Sent: Monday, April 20, 2020 2:25 AM
> To: hibernate-dev at lists.jboss.org
> Subject: Re: [hibernate-dev] HHH-13959 - OneToOne JoinTable with unique constraints work
> around?
> 
> [oops, did not mean to post the code to users]
> 
> I have narrowed it down, and I think these changes will address the issue.
> 
> commit 6ffdc4d684b33777b1c483473444d25b642e0748 (HEAD -> HHH-13959, pdinc-oss/HHH-13959)
> Author: Jason Pyeron <jpyeron at pdinc.us>
> Date:   Mon Apr 20 02:20:21 2020 -0400
> 
>     HHH-13959 Added optional awareness to FK driven OneToOne mappings
> 
>     * PropertyBinder needed optional awareness, null means don't change/set it
> 
> diff --git a/orm/hibernate-orm-5/src/test/java/org/hibernate/cfg/AnnotationBinder.java
> b/orm/hibernate-orm-5/src/test/java/org/hibernate/cfg/AnnotationBinder.java
> index eec3b49..392b8c6 100644
> --- a/orm/hibernate-orm-5/src/test/java/org/hibernate/cfg/AnnotationBinder.java
> +++ b/orm/hibernate-orm-5/src/test/java/org/hibernate/cfg/AnnotationBinder.java
> @@ -3240,6 +3240,7 @@ public final class AnnotationBinder {
>                 }
>                 else {
>                         //has a FK on the table
> +                       propertyBinder.setOptional(optional);
>                         bindManyToOne(
>                                         cascadeStrategy, joinColumns, optional,
> ignoreNotFound, cascadeOnDelete,
>                                         targetEntity,
> diff --git a/orm/hibernate-orm-
> 5/src/test/java/org/hibernate/cfg/annotations/PropertyBinder.java b/orm/hibernate-orm-
> 5/src/test/java/org/hibernate/cfg/annotations/PropertyBinder.java
> index 83c3f0c..e30946d 100644
> --- a/orm/hibernate-orm-5/src/test/java/org/hibernate/cfg/annotations/PropertyBinder.java
> +++ b/orm/hibernate-orm-5/src/test/java/org/hibernate/cfg/annotations/PropertyBinder.java
> @@ -74,6 +74,17 @@ public class PropertyBinder {
>         private EntityBinder entityBinder;
>         private boolean isXToMany;
>         private String referencedEntityName;
> +       private Boolean optional;
> +
> +       public Boolean isOptional()
> +       {
> +               return optional;
> +       }
> +
> +       public void setOptional(Boolean optional)
> +       {
> +               this.optional = optional;
> +       }
> 
>         public void setReferencedEntityName(String referencedEntityName) {
>                 this.referencedEntityName = referencedEntityName;
> @@ -328,6 +339,12 @@ public class PropertyBinder {
> 
>                 LOG.tracev( "Cascading {0} with {1}", name, cascade );
>                 this.mappingProperty = prop;
> +
> +               if (optional != null)
> +               {
> +                   prop.setOptional(optional);
> +               }
> +
>                 return prop;
>         }
> 
> -Jason
> 
> > -----Original Message-----
> > From: hibernate-dev-bounces at lists.jboss.org [mailto:hibernate-dev-
> bounces at lists.jboss.org]
> > On Behalf Of Jason Pyeron
> > Sent: Monday, April 20, 2020 1:12 AM
> > To: hibernate-users at lists.jboss.org; hibernate-dev at lists.jboss.org
> > Subject: Re: [hibernate-dev] HHH-13959 - OneToOne JoinTable with unique constraints work
> > around?
> >
> > [pardon the top post, it did not mix in well]
> >
> > It looks like [stack trace 1] the option is never set in this situation, because the
> only
> > place it is set is when
> >
> > 		if ( trueOneToOne || mapToPK || !BinderHelper.isEmptyAnnotationValue( mappedBy )
> > ) {
> >
> > but since there is a FK involved it is running
> >
> > 			//has a FK on the table
> > 			bindManyToOne(
> > 					cascadeStrategy, joinColumns, optional, ignoreNotFound,
> > cascadeOnDelete,
> > 					targetEntity,
> > 					propertyHolder, inferredData, true, isIdentifierMapper,
> > inSecondPass,
> > 					propertyBinder, context
> > 			);
> >
> > Debugging shows the optional==true. Looking at that method, the only use of optional
> > parameter is
> >
> > 		if ( !optional ) {
> > 			for ( Ejb3JoinColumn column : columns ) {
> > 				column.setNullable( false );
> > 			}
> > 		}
> >
> > Which is not relevant, since optional is true. That is the last line of code in
> > bindOneToOne(...)
> >
> > Now when the evaluation of the properties are being made to persist in the
> EntityMetamodel
> > [stack trace 2] the optional is false. As a consequence the checkNullability(...) will
> > fail with a PropertyValueException during the nullability check [stack trace 3]:
> >
> > if ( !nullability[i] && value == null ) {
> > 						//check basic level one nullablilty
> > 						throw new PropertyValueException(
> > 								"not-null property references a null or
> > transient value",
> > 								persister.getEntityName(),
> > 								persister.getPropertyNames()[i]
> > 							);
> >
> > 					}
> >
> > 1: 	AnnotationBinder.bindManyToOne(String, Ejb3JoinColumn[], boolean, boolean, boolean,
> > XClass, PropertyHolder, PropertyData, boolean, boolean, boolean, PropertyBinder,
> > MetadataBuildingContext) line: 3116
> > 	AnnotationBinder.bindOneToOne(String, Ejb3JoinColumn[], boolean, FetchMode, boolean,
> > boolean, XClass, PropertyHolder, PropertyData, String, boolean, boolean, boolean,
> > PropertyBinder, MetadataBuildingContext) line: 3243
> > 	AnnotationBinder.processElementAnnotations(PropertyHolder, Nullability, PropertyData,
> > HashMap<String,IdentifierGeneratorDefinition>, EntityBinder, boolean, boolean, boolean,
> > MetadataBuildingContext, Map<XClass,InheritanceState>) line: 1844
> > 	AnnotationBinder.processIdPropertiesIfNotAlready(Map<XClass,InheritanceState>,
> > MetadataBuildingContext, PersistentClass, EntityBinder, PropertyHolder,
> > HashMap<String,IdentifierGeneratorDefinition>, ElementsToProcess, boolean, Set<String>)
> > line: 975
> > 	AnnotationBinder.bindClass(XClass, Map<XClass,InheritanceState>,
> > MetadataBuildingContext) line: 802
> > 	AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(Set<String>) line: 254
> > 	MetadataBuildingProcess$1.processEntityHierarchies(Set<String>) line: 230
> > 	MetadataBuildingProcess.complete(ManagedResources, BootstrapContext,
> > MetadataBuildingOptions) line: 273
> > 	EntityManagerFactoryBuilderImpl.metadata() line: 1214
> > 	EntityManagerFactoryBuilderImpl.build() line: 1245
> > 	HibernatePersistenceProvider.createEntityManagerFactory(String, Map) line: 56
> > 	Persistence.createEntityManagerFactory(String, Map) line: 79
> > 	Persistence.createEntityManagerFactory(String) line: 54
> > 	JPAUnitTestCase.init() line: 27
> >
> > 2: 	PropertyFactory.buildEntityBasedAttribute(EntityPersister, SessionFactoryImplementor,
> > int, Property, boolean) line: 158
> > 	EntityMetamodel.<init>(PersistentClass, EntityPersister, SessionFactoryImplementor)
> > line: 224
> > 	SingleTableEntityPersister(AbstractEntityPersister).<init>(PersistentClass,
> > EntityDataAccess, NaturalIdDataAccess, PersisterCreationContext) line: 601
> > 	SingleTableEntityPersister.<init>(PersistentClass, EntityDataAccess,
> > NaturalIdDataAccess, PersisterCreationContext) line: 125
> > 	NativeConstructorAccessorImpl.newInstance0(Constructor<?>, Object[]) line: not
> > available [native method]
> > 	NativeConstructorAccessorImpl.newInstance(Object[]) line: not available
> > 	DelegatingConstructorAccessorImpl.newInstance(Object[]) line: not available
> > 	Constructor<T>.newInstance(Object...) line: not available
> > 	PersisterFactoryImpl.createEntityPersister(Class<EntityPersister>, PersistentClass,
> > EntityDataAccess, NaturalIdDataAccess, PersisterCreationContext) line: 96
> > 	PersisterFactoryImpl.createEntityPersister(PersistentClass, EntityDataAccess,
> > NaturalIdDataAccess, PersisterCreationContext) line: 77
> > 	MetamodelImpl.initialize(MetadataImplementor, JpaMetaModelPopulationSetting) line:
> > 181
> > 	SessionFactoryImpl.<init>(MetadataImplementor, SessionFactoryOptions) line: 299
> > 	SessionFactoryBuilderImpl.build() line: 468
> > 	EntityManagerFactoryBuilderImpl.build() line: 1249
> > 	HibernatePersistenceProvider.createEntityManagerFactory(String, Map) line: 56
> > 	Persistence.createEntityManagerFactory(String, Map) line: 79
> > 	Persistence.createEntityManagerFactory(String) line: 54
> > 	JPAUnitTestCase.init() line: 27
> >
> > 3: 	Nullability.checkNullability(Object[], EntityPersister,
> > Nullability$NullabilityCheckType) line: 92
> > 	Nullability.checkNullability(Object[], EntityPersister, boolean) line: 55
> > 	EntityIdentityInsertAction(AbstractEntityInsertAction).nullifyTransientReferencesIfNo
> > tAlready() line: 116
> > 	EntityIdentityInsertAction(AbstractEntityInsertAction).makeEntityManaged() line: 125
> > 	ActionQueue.addResolvedEntityInsertAction(AbstractEntityInsertAction) line: 289
> > 	ActionQueue.addInsertAction(AbstractEntityInsertAction) line: 263
> > 	ActionQueue.addAction(EntityIdentityInsertAction) line: 317
> > 	DefaultPersistEventListener(AbstractSaveEventListener).addInsertAction(Object[],
> > Serializable, Object, EntityPersister, boolean, EventSource, boolean) line: 330
> > 	DefaultPersistEventListener(AbstractSaveEventListener).performSaveOrReplicate(Object,
> > EntityKey, EntityPersister, boolean, Object, EventSource, boolean) line: 287
> > 	DefaultPersistEventListener(AbstractSaveEventListener).performSave(Object,
> > Serializable, EntityPersister, boolean, Object, EventSource, boolean) line: 193
> > 	DefaultPersistEventListener(AbstractSaveEventListener).saveWithGeneratedId(Object,
> > String, Object, EventSource, boolean) line: 123
> > 	DefaultPersistEventListener.entityIsTransient(PersistEvent, Map) line: 185
> > 	DefaultPersistEventListener.onPersist(PersistEvent, Map) line: 128
> > 	DefaultPersistEventListener.onPersist(PersistEvent) line: 55
> > 	1021082377.accept(Object, Object) line: not available
> > 	EventListenerGroupImpl<T>.fireEventOnEachListener(U, BiConsumer<T,U>) line: 102
> > 	SessionImpl.firePersist(PersistEvent) line: 710
> > 	SessionImpl.persist(Object) line: 696
> > 	JPAUnitTestCase.hhh13959TestProfile() line: 43
> >
> > > -----Original Message-----
> > > From: hibernate-dev-bounces at lists.jboss.org [mailto:hibernate-dev-
> > bounces at lists.jboss.org]
> > > On Behalf Of Jason Pyeron
> > > Sent: Sunday, April 19, 2020 11:18 PM
> > > To: hibernate-users at lists.jboss.org; hibernate-dev at lists.jboss.org
> > > Subject: [hibernate-dev] HHH-13959 - OneToOne JoinTable with unique constraints work
> > > around?
> > >
> > > https://hibernate.atlassian.net/browse/HHH-13959
> > >
> > >
> > >
> > > I started a DB migration today, now we are dead in the water due to this exception.
> > >
> > >
> > >
> > > When I persist an Entity on the owning side of the OneToOne(optional=true)
> relationship,
> > > and that property is null we are getting:
> > >
> > >
> > >
> > > javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null
> > > property references a null or transient value
> > >
> > >
> > >
> > > I am looking to where I can patch Hibernate or put a workaround in our code.
> > >
> > >
> > >
> > > Any help?
> > >
> > >
> > >
> > > -Jason
> > >
> > > _______________________________________________
> > > hibernate-dev mailing list
> > > hibernate-dev at lists.jboss.org
> > > https://lists.jboss.org/mailman/listinfo/hibernate-dev
> >
> >
> > _______________________________________________
> > hibernate-dev mailing list
> > hibernate-dev at lists.jboss.org
> > https://lists.jboss.org/mailman/listinfo/hibernate-dev
> 
> 
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/hibernate-dev




More information about the hibernate-dev mailing list