javax.persistence.EntityNotFoundException when using a @ManyToOne relationship and optional=true

Description

When I map a @ManyToOne relationship with optional=true, an EntityNotFoundException is thrown. According to the documentation this relationship should not be loaded.

  • Documentation of "optional": Whether the association is optional. If set to false then a non-null relationship must always exist."

The inverse means that if the parameter is set to true, a null relationship can exist. The thrown EntityNotFoundException is only understandable for me with optional=false. Is this a bug or a problem of understanding? Before switching to Hibernate 5.3.17 this mapping worked like this.

And this is the thrown exception:

_Caused by: javax.persistence.EntityNotFoundException: Unable to find ClassC with id c7bc3ad5-4017-4304-a3ff-e56e571ea6ec
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:163)
at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:285)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:180)
at org.hibernate.proxy.AbstractLazyInitializer.getIdentifier(AbstractLazyInitializer.java:89)
at org.hibernate.proxy.pojo.BasicLazyInitializer.invoke(BasicLazyInitializer.java:65)
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:43)
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
at ClassC$HibernateProxy$8ocrDHSV.getUid(Unknown Source)
at ManagerClassB.dbGetClassBById(ManagerClassB.java:39)_

Environment

None

Activity

Show:
Christian Beikov
November 25, 2020, 9:42 AM

As far as I can say, this is expected. If your FK column is set, Hibernate assumes the object exists. You can control what should happen with the @NotFound annotation: https://docs.jboss.org/hibernate/orm/5.3/javadocs/index.html?org/hibernate/annotations/NotFound.html

Martin
November 25, 2020, 10:26 AM

Thanks for your feedback. In my opinion this behaviour should also be achievable with optional=true and without using the Hibernate annotation @NotFound. Or do I interpret the optional parameter completely wrong?

Christian Beikov
November 25, 2020, 11:37 AM

It’s not specified exactly what this means, but let’s play this through. Since optional = true is the default, we’d almost always have to join every target table to check if the object actually exists to decide if we should initialize null or a proxy. This is would hurt performance significantly.

In Hibernate, we tie the nullness of an association to the nullness of the declared join column. So if the join column is not null, we assume the target row exists. To handle cases where the target row is missing, the @NotFound annotation was introduced.

The mapping you are probably looking for is an association to an inheritance entity model. Something like the following:

 

Rejected

Assignee

Christian Beikov

Reporter

Martin

Fix versions

None

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Worked in

5.1.10

Components

Affects versions

Priority

Critical