clean up logic in CHECK_ON_FLUSH

so that it's more readable/understandable

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-06-13 22:29:25 +02:00
parent 6f58c5e2f6
commit 8686392afe
2 changed files with 28 additions and 32 deletions

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.engine.internal;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.HibernateException;
import org.hibernate.TransientObjectException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
@ -296,7 +297,7 @@ public final class ForeignKeys {
* @return {@code true} if the given entity is transient (unsaved)
*/
public static boolean isTransient(
String entityName, Object entity, Boolean assumed, SharedSessionContractImplementor session) {
String entityName, Object entity, @Nullable Boolean assumed, SharedSessionContractImplementor session) {
if ( entity == UNFETCHED_PROPERTY ) {
// an unfetched association can only point to
// an entity that already exists in the db

View File

@ -378,34 +378,16 @@ public class CascadingActions {
Void context,
boolean isCascadeDeleteEnabled)
throws HibernateException {
if ( child != null
// a proxy is always non-transient
// and ForeignKeys.isTransient()
// is not written to expect a proxy
&& !isHibernateProxy( child ) ) {
// if it's associated with the session
// we are good, even if it's not yet
// inserted, since ordering problems
// are detected and handled elsewhere
final EntityEntry entry = session.getPersistenceContextInternal().getEntry( child );
if ( !isInManagedState( entry )
// TODO: check if it is a merged entity which has not yet been flushed
// Currently this throws if you directly reference a new transient
// instance after a call to merge() that results in its managed copy
// being scheduled for insertion, if the insert has not yet occurred.
// This is not terrible: it's more correct to "swap" the reference to
// point to the managed instance, but it's probably too heavy-handed.
&& ( entry != null && entry.getStatus() == Status.DELETED || isTransient( entityName, child, null, session ) ) ) {
throw new TransientObjectException( "persistent instance references an unsaved transient instance of '" +
entityName + "' (save the transient instance before flushing)" );
//TODO: should be TransientPropertyValueException
if ( child != null && isChildTransient( session, child, entityName ) ) {
throw new TransientObjectException( "persistent instance references an unsaved transient instance of '"
+ entityName + "' (save the transient instance before flushing)" );
//TODO: should be TransientPropertyValueException
// throw new TransientPropertyValueException(
// "object references an unsaved transient instance - save the transient instance before flushing",
// entityName,
// persister.getEntityName(),
// persister.getPropertyNames()[propertyIndex]
// );
}
}
}
@ -443,18 +425,31 @@ public class CascadingActions {
}
};
private static boolean isInManagedState(EntityEntry entry) {
if ( entry == null ) {
private static boolean isChildTransient(EventSource session, Object child, String entityName) {
if ( isHibernateProxy( child ) ) {
// a proxy is always non-transient
// and ForeignKeys.isTransient()
// is not written to expect a proxy
// TODO: but the proxied entity might have been deleted!
return false;
}
else {
switch ( entry.getStatus() ) {
case MANAGED:
case READ_ONLY:
case SAVING:
return true;
default:
return false;
final EntityEntry entry = session.getPersistenceContextInternal().getEntry( child );
if ( entry != null ) {
// if it's associated with the session
// we are good, even if it's not yet
// inserted, since ordering problems
// are detected and handled elsewhere
return entry.getStatus().isDeletedOrGone();
}
else {
// TODO: check if it is a merged entity which has not yet been flushed
// Currently this throws if you directly reference a new transient
// instance after a call to merge() that results in its managed copy
// being scheduled for insertion, if the insert has not yet occurred.
// This is not terrible: it's more correct to "swap" the reference to
// point to the managed instance, but it's probably too heavy-handed.
return isTransient( entityName, child, null, session );
}
}
}