HHH-15934 correctly handle @Basic(optional=false)

previously it had no effect
This commit is contained in:
Gavin 2022-12-25 18:15:56 +01:00 committed by Gavin King
parent 9e9a363154
commit 218ace291f
14 changed files with 263 additions and 251 deletions

View File

@ -18,6 +18,41 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Basic;
import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Embeddable;
import jakarta.persistence.Embedded;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.MapsId;
import jakarta.persistence.NamedNativeQueries;
import jakarta.persistence.NamedNativeQuery;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.NamedStoredProcedureQueries;
import jakarta.persistence.NamedStoredProcedureQuery;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.SequenceGenerators;
import jakarta.persistence.SqlResultSetMapping;
import jakarta.persistence.SqlResultSetMappings;
import jakarta.persistence.TableGenerator;
import jakarta.persistence.TableGenerators;
import jakarta.persistence.Version;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.MappingException; import org.hibernate.MappingException;
@ -112,42 +147,6 @@ import org.hibernate.usertype.UserType;
import org.hibernate.usertype.internal.OffsetDateTimeCompositeUserType; import org.hibernate.usertype.internal.OffsetDateTimeCompositeUserType;
import org.hibernate.usertype.internal.ZonedDateTimeCompositeUserType; import org.hibernate.usertype.internal.ZonedDateTimeCompositeUserType;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Basic;
import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Embeddable;
import jakarta.persistence.Embedded;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.MapsId;
import jakarta.persistence.NamedNativeQueries;
import jakarta.persistence.NamedNativeQuery;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.NamedStoredProcedureQueries;
import jakarta.persistence.NamedStoredProcedureQuery;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.SequenceGenerators;
import jakarta.persistence.SqlResultSetMapping;
import jakarta.persistence.SqlResultSetMappings;
import jakarta.persistence.TableGenerator;
import jakarta.persistence.TableGenerators;
import jakarta.persistence.Version;
import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull; import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull;
import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation; import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.BinderHelper.getPath; import static org.hibernate.boot.model.internal.BinderHelper.getPath;
@ -1252,7 +1251,6 @@ public final class AnnotationBinder {
isIdentifierMapper, isIdentifierMapper,
context, context,
inheritanceStatePerClass, inheritanceStatePerClass,
property,
columnsBuilder.getColumns(), columnsBuilder.getColumns(),
propertyBinder propertyBinder
); );
@ -1349,7 +1347,6 @@ public final class AnnotationBinder {
boolean isIdentifierMapper, boolean isIdentifierMapper,
MetadataBuildingContext context, MetadataBuildingContext context,
Map<XClass, InheritanceState> inheritanceStatePerClass, Map<XClass, InheritanceState> inheritanceStatePerClass,
XProperty annotatedProperty,
AnnotatedColumns columns, AnnotatedColumns columns,
PropertyBinder propertyBinder) { PropertyBinder propertyBinder) {
checkVersionProperty( propertyHolder, isIdentifierMapper ); checkVersionProperty( propertyHolder, isIdentifierMapper );
@ -1565,32 +1562,12 @@ public final class AnnotationBinder {
AnnotatedColumns columns, AnnotatedColumns columns,
PropertyBinder propertyBinder, PropertyBinder propertyBinder,
boolean isOverridden) { boolean isOverridden) {
//provide the basic property mapping
final boolean optional; if ( shouldForceNotNull( nullability, propertyBinder, isOptional( property ) ) ) {
final boolean lazy; forceColumnsNotNull( propertyHolder, inferredData, columns, propertyBinder );
if ( property.isAnnotationPresent( Basic.class ) ) {
final Basic basic = property.getAnnotation( Basic.class );
optional = basic.optional();
lazy = basic.fetch() == FetchType.LAZY;
}
else {
optional = true;
lazy = false;
} }
//implicit type will check basic types and Serializable classes propertyBinder.setLazy( BasicValueBinder.isLazy( property ) );
if ( propertyBinder.isId() || !optional && nullability != Nullability.FORCED_NULL ) {
//force columns to not null
for ( AnnotatedColumn column : columns.getColumns() ) {
if ( propertyBinder.isId() && column.isFormula() ) {
throw new CannotForceNonNullableException( "Identifier property '"
+ getPath( propertyHolder, inferredData ) + "' cannot map to a '@Formula'" );
}
column.forceNotNull();
}
}
propertyBinder.setLazy( lazy );
propertyBinder.setColumns( columns ); propertyBinder.setColumns( columns );
if ( isOverridden ) { if ( isOverridden ) {
final PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId( final PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId(
@ -1605,6 +1582,36 @@ public final class AnnotationBinder {
propertyBinder.makePropertyValueAndBind(); propertyBinder.makePropertyValueAndBind();
} }
private static void forceColumnsNotNull(
PropertyHolder propertyHolder,
PropertyData inferredData,
AnnotatedColumns columns,
PropertyBinder propertyBinder) {
for ( AnnotatedColumn column : columns.getColumns() ) {
if ( propertyBinder.isId() && column.isFormula() ) {
throw new CannotForceNonNullableException( "Identifier property '"
+ getPath( propertyHolder, inferredData ) + "' cannot map to a '@Formula'" );
}
column.forceNotNull();
}
}
private static boolean shouldForceNotNull(Nullability nullability, PropertyBinder propertyBinder, boolean optional) {
return propertyBinder.isId()
|| !optional && nullability != Nullability.FORCED_NULL;
}
static boolean isOptional(XProperty property) {
if ( property.isAnnotationPresent( Basic.class ) ) {
final Basic basic = property.getAnnotation( Basic.class );
return basic.optional();
}
else {
return true;
}
}
private static PropertyBinder createCompositeBinder( private static PropertyBinder createCompositeBinder(
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData, PropertyData inferredData,

View File

@ -14,6 +14,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import jakarta.persistence.Basic;
import jakarta.persistence.FetchType;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.MappingException; import org.hibernate.MappingException;
@ -105,6 +107,26 @@ public class BasicValueBinder implements JdbcTypeIndicators {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, BasicValueBinder.class.getName() ); private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, BasicValueBinder.class.getName() );
static boolean isOptional(XProperty property) {
if ( property.isAnnotationPresent( Basic.class ) ) {
final Basic basic = property.getAnnotation( Basic.class );
return basic.optional();
}
else {
return property.isArray() || !property.getClassOrElementClass().isPrimitive();
}
}
static boolean isLazy(XProperty property) {
if ( property.isAnnotationPresent( Basic.class ) ) {
final Basic basic = property.getAnnotation( Basic.class );
return basic.fetch() == FetchType.LAZY;
}
else {
return false;
}
}
public enum Kind { public enum Kind {
ATTRIBUTE( ValueMappingAccess.INSTANCE ), ATTRIBUTE( ValueMappingAccess.INSTANCE ),
ANY_DISCRIMINATOR( AnyDiscriminatorMappingAccess.INSTANCE ), ANY_DISCRIMINATOR( AnyDiscriminatorMappingAccess.INSTANCE ),
@ -143,7 +165,6 @@ public class BasicValueBinder implements JdbcTypeIndicators {
private ConverterDescriptor converterDescriptor; private ConverterDescriptor converterDescriptor;
private boolean isVersion;
private boolean isNationalized; private boolean isNationalized;
private boolean isLob; private boolean isLob;
private EnumType enumType; private EnumType enumType;
@ -266,7 +287,6 @@ public class BasicValueBinder implements JdbcTypeIndicators {
// in-flight handling // in-flight handling
public void setVersion(boolean isVersion) { public void setVersion(boolean isVersion) {
this.isVersion = isVersion;
if ( isVersion && basicValue != null ) { if ( isVersion && basicValue != null ) {
basicValue.makeVersion(); basicValue.makeVersion();
} }
@ -511,7 +531,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
}; };
// todo (6.0) - handle generator // todo (6.0) - handle generator
final String generator = collectionIdAnn.generator(); // final String generator = collectionIdAnn.generator();
} }
private ManagedBeanRegistry getManagedBeanRegistry() { private ManagedBeanRegistry getManagedBeanRegistry() {
@ -523,17 +543,9 @@ public class BasicValueBinder implements JdbcTypeIndicators {
private void prepareMapKey( private void prepareMapKey(
XProperty mapAttribute, XProperty mapAttribute,
XClass modelPropertyTypeXClass) { XClass modelPropertyTypeXClass) {
final XClass mapKeyClass; final XClass mapKeyClass = modelPropertyTypeXClass == null ? mapAttribute.getMapKey() : modelPropertyTypeXClass;
if ( modelPropertyTypeXClass == null ) {
mapKeyClass = mapAttribute.getMapKey();
}
else {
mapKeyClass = modelPropertyTypeXClass;
}
final java.lang.reflect.Type javaType = resolveJavaType( mapKeyClass ); final java.lang.reflect.Type javaType = resolveJavaType( mapKeyClass );
final Class<Object> javaTypeClass = ReflectHelper.getClass( javaType ); implicitJavaTypeAccess = typeConfiguration -> javaType;
implicitJavaTypeAccess = (typeConfiguration) -> javaType;
final MapKeyEnumerated mapKeyEnumeratedAnn = mapAttribute.getAnnotation( MapKeyEnumerated.class ); final MapKeyEnumerated mapKeyEnumeratedAnn = mapAttribute.getAnnotation( MapKeyEnumerated.class );
if ( mapKeyEnumeratedAnn != null ) { if ( mapKeyEnumeratedAnn != null ) {
@ -570,8 +582,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
if ( javaTypeAnn != null ) { if ( javaTypeAnn != null ) {
final Class<? extends BasicJavaType<?>> jdbcTypeImpl = normalizeJavaType( javaTypeAnn.value() ); final Class<? extends BasicJavaType<?>> jdbcTypeImpl = normalizeJavaType( javaTypeAnn.value() );
if ( jdbcTypeImpl != null ) { if ( jdbcTypeImpl != null ) {
final ManagedBean<? extends BasicJavaType> jdbcTypeBean = getManagedBeanRegistry().getBean( jdbcTypeImpl ); return getManagedBeanRegistry().getBean( jdbcTypeImpl ).getBeanInstance();
return jdbcTypeBean.getBeanInstance();
} }
} }

View File

@ -1629,6 +1629,7 @@ public abstract class CollectionBinder {
+ '_' + foreignJoinColumns.getColumns().get(0).getLogicalColumnName() + '_' + foreignJoinColumns.getColumns().get(0).getLogicalColumnName()
+ "Backref"; + "Backref";
backref.setName( backrefName ); backref.setName( backrefName );
backref.setOptional( true );
backref.setUpdateable( false); backref.setUpdateable( false);
backref.setSelectable( false ); backref.setSelectable( false );
backref.setCollectionRole( collection.getRole() ); backref.setCollectionRole( collection.getRole() );

View File

@ -104,6 +104,7 @@ public class ListBinder extends CollectionBinder {
final PersistentClass referenced = buildingContext.getMetadataCollector().getEntityBinding( entityName ); final PersistentClass referenced = buildingContext.getMetadataCollector().getEntityBinding( entityName );
final IndexBackref backref = new IndexBackref(); final IndexBackref backref = new IndexBackref();
backref.setName( '_' + propertyName + "IndexBackref" ); backref.setName( '_' + propertyName + "IndexBackref" );
backref.setOptional( true );
backref.setUpdateable( false ); backref.setUpdateable( false );
backref.setSelectable( false ); backref.setSelectable( false );
backref.setCollectionRole( collection.getRole() ); backref.setCollectionRole( collection.getRole() );

View File

@ -55,6 +55,7 @@ import jakarta.persistence.Id;
import jakarta.persistence.Lob; import jakarta.persistence.Lob;
import jakarta.persistence.Version; import jakarta.persistence.Version;
import static org.hibernate.boot.model.internal.BasicValueBinder.isOptional;
import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull; import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull;
import static org.hibernate.boot.model.internal.HCANNHelper.findContainingAnnotation; import static org.hibernate.boot.model.internal.HCANNHelper.findContainingAnnotation;
import static org.hibernate.internal.util.StringHelper.qualify; import static org.hibernate.internal.util.StringHelper.qualify;
@ -324,19 +325,15 @@ public class PropertyBinder {
} }
private Class<? extends EmbeddableInstantiator> resolveCustomInstantiator(XProperty property, XClass embeddableClass) { private Class<? extends EmbeddableInstantiator> resolveCustomInstantiator(XProperty property, XClass embeddableClass) {
final org.hibernate.annotations.EmbeddableInstantiator propertyAnnotation = if ( property.isAnnotationPresent( org.hibernate.annotations.EmbeddableInstantiator.class ) ) {
property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); return property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ).value();
if ( propertyAnnotation != null ) {
return propertyAnnotation.value();
} }
else if ( property.isAnnotationPresent( org.hibernate.annotations.EmbeddableInstantiator.class ) ) {
final org.hibernate.annotations.EmbeddableInstantiator classAnnotation = return embeddableClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ).value();
embeddableClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); }
if ( classAnnotation != null ) { else {
return classAnnotation.value(); return null;
} }
return null;
} }
//used when the value is provided and the binding is done elsewhere //used when the value is provided and the binding is done elsewhere
@ -351,48 +348,58 @@ public class PropertyBinder {
property.setCascade( cascade ); property.setCascade( cascade );
property.setPropertyAccessorName( accessType.getType() ); property.setPropertyAccessorName( accessType.getType() );
property.setReturnedClassName( returnedClassName ); property.setReturnedClassName( returnedClassName );
if ( this.property != null ) {
if ( entityBinder != null ) {
handleNaturalId( property );
property.setValueGeneratorCreator( getValueGenerationFromAnnotations( this.property ) );
}
// HHH-4635 -- needed for dialect-specific property ordering
property.setLob( this.property.isAnnotationPresent( Lob.class ) );
}
property.setPropertyAccessStrategy( propertyAccessStrategy ); property.setPropertyAccessStrategy( propertyAccessStrategy );
handleValueGeneration( property );
handleImmutable( property ); handleNaturalId( property );
handleLob( property );
handleMutability( property );
handleOptional( property );
inferOptimisticLocking( property ); inferOptimisticLocking( property );
property.setInsertable( insertable );
property.setUpdateable( updatable );
LOG.tracev( "Cascading {0} with {1}", name, cascade ); LOG.tracev( "Cascading {0} with {1}", name, cascade );
return property; return property;
} }
private void handleImmutable(Property property) { private void handleValueGeneration(Property property) {
if ( this.property!=null ) {
property.setValueGeneratorCreator( getValueGenerationFromAnnotations( this.property ) );
}
}
private void handleLob(Property property) {
if ( this.property != null ) {
// HHH-4635 -- needed for dialect-specific property ordering
property.setLob( this.property.isAnnotationPresent( Lob.class ) );
}
}
private void handleMutability(Property property) {
if ( this.property != null && this.property.isAnnotationPresent( Immutable.class ) ) { if ( this.property != null && this.property.isAnnotationPresent( Immutable.class ) ) {
updatable = false; updatable = false;
} }
property.setInsertable( insertable );
property.setUpdateable( updatable );
}
private void handleOptional(Property property) {
if ( this.property != null ) {
property.setOptional( !isId && isOptional( this.property ) );
}
} }
private void handleNaturalId(Property property) { private void handleNaturalId(Property property) {
final NaturalId naturalId = this.property.getAnnotation(NaturalId.class); if ( this.property != null && entityBinder != null ) {
if ( naturalId != null ) { final NaturalId naturalId = this.property.getAnnotation( NaturalId.class );
if ( !entityBinder.isRootEntity() ) { if ( naturalId != null ) {
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name ) if ( !entityBinder.isRootEntity() ) {
+ "' belongs to an entity subclass and may not be annotated '@NaturalId'" + throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
" (only a property of a root '@Entity' or a '@MappedSuperclass' may be a '@NaturalId')" ); + "' belongs to an entity subclass and may not be annotated '@NaturalId'" +
" (only a property of a root '@Entity' or a '@MappedSuperclass' may be a '@NaturalId')" );
}
if ( !naturalId.mutable() ) {
updatable = false;
}
property.setNaturalIdentifier( true );
} }
if ( !naturalId.mutable() ) {
updatable = false;
}
property.setNaturalIdentifier( true );
} }
} }
@ -401,8 +408,8 @@ public class PropertyBinder {
if ( value instanceof Collection ) { if ( value instanceof Collection ) {
property.setOptimisticLocked( ((Collection) value).isOptimisticLocked() ); property.setOptimisticLocked( ((Collection) value).isOptimisticLocked() );
} }
else if ( this.property != null && this.property.isAnnotationPresent(OptimisticLock.class) ) { else if ( this.property != null && this.property.isAnnotationPresent( OptimisticLock.class ) ) {
final OptimisticLock optimisticLock = this.property.getAnnotation(OptimisticLock.class); final OptimisticLock optimisticLock = this.property.getAnnotation( OptimisticLock.class );
validateOptimisticLock( optimisticLock ); validateOptimisticLock( optimisticLock );
property.setOptimisticLocked( !optimisticLock.excluded() ); property.setOptimisticLocked( !optimisticLock.excluded() );
} }
@ -413,15 +420,15 @@ public class PropertyBinder {
private void validateOptimisticLock(OptimisticLock optimisticLock) { private void validateOptimisticLock(OptimisticLock optimisticLock) {
if ( optimisticLock.excluded() ) { if ( optimisticLock.excluded() ) {
if ( property.isAnnotationPresent(Version.class) ) { if ( property.isAnnotationPresent( Version.class ) ) {
throw new AnnotationException("Property '" + qualify( holder.getPath(), name ) throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
+ "' is annotated '@OptimisticLock(excluded=true)' and '@Version'" ); + "' is annotated '@OptimisticLock(excluded=true)' and '@Version'" );
} }
if ( property.isAnnotationPresent(Id.class) ) { if ( property.isAnnotationPresent( Id.class ) ) {
throw new AnnotationException("Property '" + qualify( holder.getPath(), name ) throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
+ "' is annotated '@OptimisticLock(excluded=true)' and '@Id'" ); + "' is annotated '@OptimisticLock(excluded=true)' and '@Id'" );
} }
if ( property.isAnnotationPresent(EmbeddedId.class) ) { if ( property.isAnnotationPresent( EmbeddedId.class ) ) {
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name ) throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
+ "' is annotated '@OptimisticLock(excluded=true)' and '@EmbeddedId'" ); + "' is annotated '@OptimisticLock(excluded=true)' and '@EmbeddedId'" );
} }

View File

@ -94,11 +94,10 @@ public class ToOneBinder {
joinColumn.setExplicitTableName( join.getTable().getName() ); joinColumn.setExplicitTableName( join.getTable().getName() );
} }
} }
final boolean mandatory = isMandatory( manyToOne.optional(), property, notFoundAction );
bindManyToOne( bindManyToOne(
getCascadeStrategy( manyToOne.cascade(), hibernateCascade, false, forcePersist ), getCascadeStrategy( manyToOne.cascade(), hibernateCascade, false, forcePersist ),
joinColumns, joinColumns,
!mandatory, !isMandatory( manyToOne.optional(), property, notFoundAction ),
notFoundAction, notFoundAction,
onDelete == null ? null : onDelete.action(), onDelete == null ? null : onDelete.action(),
getTargetEntity( inferredData, context ), getTargetEntity( inferredData, context ),

View File

@ -1090,6 +1090,7 @@ public class ModelBinder {
(PluralAttributeSource) attributeSource, (PluralAttributeSource) attributeSource,
entityDescriptor entityDescriptor
); );
attribute.setOptional( true );
entityDescriptor.addProperty( attribute ); entityDescriptor.addProperty( attribute );
} }
else { else {
@ -1116,9 +1117,7 @@ public class ModelBinder {
entityDescriptor.getClassName() entityDescriptor.getClassName()
); );
if ( secondaryTableJoin != null ) { attribute.setOptional( isOptional( secondaryTableJoin, attribute ) );
attribute.setOptional( secondaryTableJoin.isOptional() );
}
attributeContainer.addProperty( attribute ); attributeContainer.addProperty( attribute );
@ -1151,9 +1150,7 @@ public class ModelBinder {
entityDescriptor.getClassName() entityDescriptor.getClassName()
); );
if ( secondaryTableJoin != null ) { attribute.setOptional( isOptional( secondaryTableJoin, attribute ) );
attribute.setOptional( secondaryTableJoin.isOptional() );
}
attributeContainer.addProperty( attribute ); attributeContainer.addProperty( attribute );
@ -1186,9 +1183,7 @@ public class ModelBinder {
entityDescriptor.getClassName() entityDescriptor.getClassName()
); );
if ( secondaryTableJoin != null ) { attribute.setOptional( isOptional( secondaryTableJoin, attribute ) );
attribute.setOptional( secondaryTableJoin.isOptional() );
}
attributeContainer.addProperty( attribute ); attributeContainer.addProperty( attribute );
@ -1208,6 +1203,9 @@ public class ModelBinder {
new OneToOne( mappingDocument, table, entityDescriptor ), new OneToOne( mappingDocument, table, entityDescriptor ),
entityDescriptor.getClassName() entityDescriptor.getClassName()
); );
attribute.setOptional( attribute.getValue().isNullable() );
entityDescriptor.addProperty( attribute ); entityDescriptor.addProperty( attribute );
handleNaturalIdBinding( handleNaturalIdBinding(
@ -1243,9 +1241,7 @@ public class ModelBinder {
entityDescriptor.getEntityName() entityDescriptor.getEntityName()
); );
if ( secondaryTableJoin != null ) { attribute.setOptional( isOptional( secondaryTableJoin, attribute ) );
attribute.setOptional( secondaryTableJoin.isOptional() );
}
attributeContainer.addProperty( attribute ); attributeContainer.addProperty( attribute );
@ -1260,6 +1256,11 @@ public class ModelBinder {
} }
} }
private static boolean isOptional(Join secondaryTableJoin, Property attribute) {
return secondaryTableJoin != null && secondaryTableJoin.isOptional()
|| attribute.getValue().isNullable();
}
private void handleNaturalIdBinding( private void handleNaturalIdBinding(
MappingDocument mappingDocument, MappingDocument mappingDocument,
PersistentClass entityBinding, PersistentClass entityBinding,
@ -2785,6 +2786,8 @@ public class ModelBinder {
); );
} }
attribute.setOptional( attribute.getValue().isNullable() );
component.addProperty( attribute ); component.addProperty( attribute );
} }
} }
@ -3286,19 +3289,20 @@ public class ModelBinder {
// for non-inverse one-to-many, with a not-null fk, add a backref! // for non-inverse one-to-many, with a not-null fk, add a backref!
final String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName(); final String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName();
final PersistentClass referenced = getReferencedEntityBinding( entityName ); final PersistentClass referenced = getReferencedEntityBinding( entityName );
final Backref prop = new Backref(); final Backref backref = new Backref();
prop.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "Backref" ); backref.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "Backref" );
prop.setUpdateable( false ); backref.setOptional( true );
prop.setSelectable( false ); backref.setUpdateable( false );
prop.setCollectionRole( collectionBinding.getRole() ); backref.setSelectable( false );
prop.setEntityName( collectionBinding.getOwner().getEntityName() ); backref.setCollectionRole( collectionBinding.getRole() );
prop.setValue( collectionBinding.getKey() ); backref.setEntityName( collectionBinding.getOwner().getEntityName() );
referenced.addProperty( prop ); backref.setValue( collectionBinding.getKey() );
referenced.addProperty( backref );
if ( log.isDebugEnabled() ) { if ( log.isDebugEnabled() ) {
log.debugf( log.debugf(
"Added virtual backref property [%s] : %s", "Added virtual backref property [%s] : %s",
prop.getName(), backref.getName(),
pluralAttributeSource.getAttributeRole().getFullPath() pluralAttributeSource.getAttributeRole().getFullPath()
); );
} }
@ -3748,14 +3752,15 @@ public class ModelBinder {
&& !indexIsFormula ) { && !indexIsFormula ) {
final String entityName = ( (OneToMany) getCollectionBinding().getElement() ).getReferencedEntityName(); final String entityName = ( (OneToMany) getCollectionBinding().getElement() ).getReferencedEntityName();
final PersistentClass referenced = getMappingDocument().getMetadataCollector().getEntityBinding( entityName ); final PersistentClass referenced = getMappingDocument().getMetadataCollector().getEntityBinding( entityName );
final IndexBackref ib = new IndexBackref(); final IndexBackref backref = new IndexBackref();
ib.setName( '_' + getCollectionBinding().getOwnerEntityName() + "." + getPluralAttributeSource().getName() + "IndexBackref" ); backref.setName( '_' + getCollectionBinding().getOwnerEntityName() + "." + getPluralAttributeSource().getName() + "IndexBackref" );
ib.setUpdateable( false ); backref.setOptional( true );
ib.setSelectable( false ); backref.setUpdateable( false );
ib.setCollectionRole( getCollectionBinding().getRole() ); backref.setSelectable( false );
ib.setEntityName( getCollectionBinding().getOwner().getEntityName() ); backref.setCollectionRole( getCollectionBinding().getRole() );
ib.setValue( getCollectionBinding().getIndex() ); backref.setEntityName( getCollectionBinding().getOwner().getEntityName() );
referenced.addProperty( ib ); backref.setValue( getCollectionBinding().getIndex() );
referenced.addProperty( backref );
} }
} }
} }
@ -3826,14 +3831,15 @@ public class ModelBinder {
&& !collectionBinding.isInverse() ) { && !collectionBinding.isInverse() ) {
final String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName(); final String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName();
final PersistentClass referenced = mappingDocument.getMetadataCollector().getEntityBinding( entityName ); final PersistentClass referenced = mappingDocument.getMetadataCollector().getEntityBinding( entityName );
final IndexBackref ib = new IndexBackref(); final IndexBackref backref = new IndexBackref();
ib.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "IndexBackref" ); backref.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "IndexBackref" );
ib.setUpdateable( false ); backref.setOptional( true );
ib.setSelectable( false ); backref.setUpdateable( false );
ib.setCollectionRole( collectionBinding.getRole() ); backref.setSelectable( false );
ib.setEntityName( collectionBinding.getOwner().getEntityName() ); backref.setCollectionRole( collectionBinding.getRole() );
ib.setValue( collectionBinding.getIndex() ); backref.setEntityName( collectionBinding.getOwner().getEntityName() );
referenced.addProperty( ib ); backref.setValue( collectionBinding.getIndex() );
referenced.addProperty( backref );
} }
} }

View File

@ -8,8 +8,6 @@ package org.hibernate.loader.ast.internal;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -31,7 +29,6 @@ import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.loader.ast.spi.Loadable; import org.hibernate.loader.ast.spi.Loadable;
import org.hibernate.loader.ast.spi.Loader; import org.hibernate.loader.ast.spi.Loader;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
@ -56,7 +53,6 @@ import org.hibernate.sql.ast.spi.SimpleFromClauseAccessImpl;
import org.hibernate.sql.ast.spi.SqlAliasBaseManager; import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlAstQueryPartProcessingState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
@ -89,8 +85,8 @@ import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static java.util.Collections.singletonList;
import static org.hibernate.query.results.ResultsHelper.attributeName; import static org.hibernate.query.results.ResultsHelper.attributeName;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
/** /**
* Builder for SQL AST trees used by {@link Loader} implementations. * Builder for SQL AST trees used by {@link Loader} implementations.
@ -128,7 +124,7 @@ public class LoaderSelectBuilder {
sessionFactory, sessionFactory,
loadable, loadable,
partsToSelect, partsToSelect,
Collections.singletonList( restrictedPart ), singletonList( restrictedPart ),
cachedDomainResult, cachedDomainResult,
numberOfKeysToLoad, numberOfKeysToLoad,
loadQueryInfluencers, loadQueryInfluencers,
@ -220,7 +216,7 @@ public class LoaderSelectBuilder {
public static SelectStatement createSubSelectFetchSelect( public static SelectStatement createSubSelectFetchSelect(
PluralAttributeMapping attributeMapping, PluralAttributeMapping attributeMapping,
SubselectFetch subselect, SubselectFetch subselect,
DomainResult cachedDomainResult, DomainResult<?> cachedDomainResult,
LoadQueryInfluencers loadQueryInfluencers, LoadQueryInfluencers loadQueryInfluencers,
LockOptions lockOptions, LockOptions lockOptions,
Consumer<JdbcParameter> jdbcParameterConsumer, Consumer<JdbcParameter> jdbcParameterConsumer,
@ -244,7 +240,7 @@ public class LoaderSelectBuilder {
private final Loadable loadable; private final Loadable loadable;
private final List<? extends ModelPart> partsToSelect; private final List<? extends ModelPart> partsToSelect;
private final List<ModelPart> restrictedParts; private final List<ModelPart> restrictedParts;
private final DomainResult cachedDomainResult; private final DomainResult<?> cachedDomainResult;
private final int numberOfKeysToLoad; private final int numberOfKeysToLoad;
private final boolean forceIdentifierSelection; private final boolean forceIdentifierSelection;
private final LoadQueryInfluencers loadQueryInfluencers; private final LoadQueryInfluencers loadQueryInfluencers;
@ -262,7 +258,7 @@ public class LoaderSelectBuilder {
Loadable loadable, Loadable loadable,
List<? extends ModelPart> partsToSelect, List<? extends ModelPart> partsToSelect,
List<ModelPart> restrictedParts, List<ModelPart> restrictedParts,
DomainResult cachedDomainResult, DomainResult<?> cachedDomainResult,
int numberOfKeysToLoad, int numberOfKeysToLoad,
LoadQueryInfluencers loadQueryInfluencers, LoadQueryInfluencers loadQueryInfluencers,
LockOptions lockOptions, LockOptions lockOptions,
@ -287,7 +283,7 @@ public class LoaderSelectBuilder {
Loadable loadable, Loadable loadable,
List<? extends ModelPart> partsToSelect, List<? extends ModelPart> partsToSelect,
List<ModelPart> restrictedParts, List<ModelPart> restrictedParts,
DomainResult cachedDomainResult, DomainResult<?> cachedDomainResult,
int numberOfKeysToLoad, int numberOfKeysToLoad,
LoadQueryInfluencers loadQueryInfluencers, LoadQueryInfluencers loadQueryInfluencers,
LockOptions lockOptions, LockOptions lockOptions,
@ -312,7 +308,7 @@ public class LoaderSelectBuilder {
Loadable loadable, Loadable loadable,
List<? extends ModelPart> partsToSelect, List<? extends ModelPart> partsToSelect,
ModelPart restrictedPart, ModelPart restrictedPart,
DomainResult cachedDomainResult, DomainResult<?> cachedDomainResult,
int numberOfKeysToLoad, int numberOfKeysToLoad,
LoadQueryInfluencers loadQueryInfluencers, LoadQueryInfluencers loadQueryInfluencers,
LockOptions lockOptions, LockOptions lockOptions,
@ -321,7 +317,7 @@ public class LoaderSelectBuilder {
creationContext, creationContext,
loadable, loadable,
partsToSelect, partsToSelect,
Arrays.asList( restrictedPart ), singletonList( restrictedPart ),
cachedDomainResult, cachedDomainResult,
numberOfKeysToLoad, numberOfKeysToLoad,
loadQueryInfluencers, loadQueryInfluencers,
@ -356,7 +352,7 @@ public class LoaderSelectBuilder {
final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph(); final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph();
if ( effectiveEntityGraph != null ) { if ( effectiveEntityGraph != null ) {
final GraphSemantic graphSemantic = effectiveEntityGraph.getSemantic(); final GraphSemantic graphSemantic = effectiveEntityGraph.getSemantic();
final RootGraphImplementor rootGraphImplementor = effectiveEntityGraph.getGraph(); final RootGraphImplementor<?> rootGraphImplementor = effectiveEntityGraph.getGraph();
if ( graphSemantic != null && rootGraphImplementor != null ) { if ( graphSemantic != null && rootGraphImplementor != null ) {
return new StandardEntityGraphTraversalStateImpl( graphSemantic, rootGraphImplementor ); return new StandardEntityGraphTraversalStateImpl( graphSemantic, rootGraphImplementor );
} }
@ -458,7 +454,7 @@ public class LoaderSelectBuilder {
} }
//noinspection unchecked //noinspection unchecked
domainResults = Collections.singletonList( domainResult ); domainResults = singletonList( domainResult );
} }
for ( ModelPart restrictedPart : restrictedParts ) { for ( ModelPart restrictedPart : restrictedParts ) {
@ -655,11 +651,7 @@ public class LoaderSelectBuilder {
} }
final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchParent.getReferencedMappingContainer() ); final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchParent.getReferencedMappingContainer() );
final BiConsumer<Fetchable, Boolean> processor = createFetchableBiConsumer( final BiConsumer<Fetchable, Boolean> processor = createFetchableBiConsumer( fetchParent, creationState, fetches );
fetchParent,
creationState,
fetches
);
final FetchableContainer referencedMappingContainer = fetchParent.getReferencedMappingContainer(); final FetchableContainer referencedMappingContainer = fetchParent.getReferencedMappingContainer();
if ( fetchParent.getNavigablePath().getParent() != null ) { if ( fetchParent.getNavigablePath().getParent() != null ) {
@ -759,7 +751,7 @@ public class LoaderSelectBuilder {
else if ( loadQueryInfluencers.getEnabledCascadingFetchProfile() != null ) { else if ( loadQueryInfluencers.getEnabledCascadingFetchProfile() != null ) {
final CascadeStyle cascadeStyle = fetchable.asAttributeMapping().getAttributeMetadata() final CascadeStyle cascadeStyle = fetchable.asAttributeMapping().getAttributeMetadata()
.getCascadeStyle(); .getCascadeStyle();
final CascadingAction cascadingAction = loadQueryInfluencers.getEnabledCascadingFetchProfile() final CascadingAction<?> cascadingAction = loadQueryInfluencers.getEnabledCascadingFetchProfile()
.getCascadingAction(); .getCascadingAction();
if ( cascadeStyle == null || cascadeStyle.doCascade( cascadingAction ) ) { if ( cascadeStyle == null || cascadeStyle.doCascade( cascadingAction ) ) {
fetchTiming = FetchTiming.IMMEDIATE; fetchTiming = FetchTiming.IMMEDIATE;
@ -853,7 +845,6 @@ public class LoaderSelectBuilder {
creationState creationState
); );
applyOrdering( applyOrdering(
querySpec,
fetchablePath, fetchablePath,
pluralAttributeMapping, pluralAttributeMapping,
creationState creationState
@ -901,7 +892,6 @@ public class LoaderSelectBuilder {
} }
private void applyOrdering( private void applyOrdering(
QuerySpec ast,
NavigablePath navigablePath, NavigablePath navigablePath,
PluralAttributeMapping pluralAttributeMapping, PluralAttributeMapping pluralAttributeMapping,
LoaderSqlAstCreationState sqlAstCreationState) { LoaderSqlAstCreationState sqlAstCreationState) {
@ -988,7 +978,7 @@ public class LoaderSelectBuilder {
return new SelectStatement( return new SelectStatement(
rootQuerySpec, rootQuerySpec,
List.of( singletonList(
new CollectionDomainResult( new CollectionDomainResult(
rootNavigablePath, rootNavigablePath,
attributeMapping, attributeMapping,
@ -1006,9 +996,6 @@ public class LoaderSelectBuilder {
TableGroup rootTableGroup, TableGroup rootTableGroup,
SubselectFetch subselect, SubselectFetch subselect,
LoaderSqlAstCreationState sqlAstCreationState) { LoaderSqlAstCreationState sqlAstCreationState) {
final SqlAstCreationContext sqlAstCreationContext = sqlAstCreationState.getCreationContext();
final SessionFactoryImplementor sessionFactory = sqlAstCreationContext.getSessionFactory();
assert loadable instanceof PluralAttributeMapping; assert loadable instanceof PluralAttributeMapping;
final PluralAttributeMapping attributeMapping = (PluralAttributeMapping) loadable; final PluralAttributeMapping attributeMapping = (PluralAttributeMapping) loadable;
@ -1053,11 +1040,8 @@ public class LoaderSelectBuilder {
fkExpression, fkExpression,
generateSubSelect( generateSubSelect(
attributeMapping, attributeMapping,
rootTableGroup,
subselect, subselect,
jdbcTypeCount, sqlAstCreationState
sqlAstCreationState,
sessionFactory
), ),
false false
) )
@ -1066,11 +1050,8 @@ public class LoaderSelectBuilder {
private QueryPart generateSubSelect( private QueryPart generateSubSelect(
PluralAttributeMapping attributeMapping, PluralAttributeMapping attributeMapping,
TableGroup rootTableGroup,
SubselectFetch subselect, SubselectFetch subselect,
int jdbcTypeCount, LoaderSqlAstCreationState creationState) {
LoaderSqlAstCreationState creationState,
SessionFactoryImplementor sessionFactory) {
final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor(); final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor();
final QuerySpec subQuery = new QuerySpec( false ); final QuerySpec subQuery = new QuerySpec( false );

View File

@ -7,7 +7,6 @@
package org.hibernate.loader.ast.internal; package org.hibernate.loader.ast.internal;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.sql.exec.internal.BaseExecutionContext; import org.hibernate.sql.exec.internal.BaseExecutionContext;
import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.Callback;
@ -19,7 +18,8 @@ public class NoCallbackExecutionContext extends BaseExecutionContext {
@Override @Override
public Callback getCallback() { public Callback getCallback() {
throw new UnsupportedOperationException( "Follow-on locking not supported yet" ); return null;
// throw new UnsupportedOperationException( "Follow-on locking not supported yet" );
} }
} }

View File

@ -16,7 +16,6 @@ import java.util.StringTokenizer;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.Database;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper;
import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.CascadeStyle;
@ -138,12 +137,16 @@ public class Property implements Serializable, MetaAttributable {
} }
} }
public boolean isPrimitive(Class clazz) { /**
return getGetter(clazz).getReturnTypeClass().isPrimitive(); * @deprecated this method is no longer used
*/
@Deprecated(since = "6", forRemoval = true)
public boolean isPrimitive(Class<?> clazz) {
return getGetter( clazz ).getReturnTypeClass().isPrimitive();
} }
public CascadeStyle getCascadeStyle() throws MappingException { public CascadeStyle getCascadeStyle() throws MappingException {
Type type = value.getType(); final Type type = value.getType();
if ( type.isComponentType() ) { if ( type.isComponentType() ) {
return getCompositeCascadeStyle( (CompositeType) type, cascade ); return getCompositeCascadeStyle( (CompositeType) type, cascade );
} }
@ -292,28 +295,27 @@ public class Property implements Serializable, MetaAttributable {
/** /**
* Is this property lazy in the "bytecode" sense? * Is this property lazy in the "bytecode" sense?
* <p> * <p>
* Lazy here means whether we should push *something* to the entity * Lazy here means whether we initialize this field of the entity
* instance for this field in its "base fetch group". Mainly it affects * instance in its "base fetch group". It affects whether we list
* whether we should list this property's columns in the SQL select * this property's columns in the SQL select for the owning entity
* for the owning entity when we load its "base fetch group". * when we load its "base fetch group". The actual value that is set
* <p> * varies based on the nature (basic, etc) of the property.
* The "something" we push varies based on the nature (basic, etc) of
* the property.
* *
* @apiNote This form reports whether the property is considered part of the * @apiNote This method reports whether the property is considered
* base fetch group based solely on the mapping information. However, * part of the base fetch group based solely on the information in
* {@link EnhancementHelper#includeInBaseFetchGroup} is used internally to make that * the mapping but {@link EnhancementHelper#includeInBaseFetchGroup}
* decision to account for other details * is also accounts for other details.
*/ */
public boolean isLazy() { public boolean isLazy() {
if ( value instanceof ToOne ) { if ( value instanceof ToOne ) {
// For a many-to-one, this is always false. Whether the // For a many-to-one, this is always false. Whether the
// association is EAGER, PROXY or NO-PROXY we want the fk // association is EAGER, PROXY or NO-PROXY we always want
// selected // to select the foreign key
return false; return false;
} }
else {
return lazy; return lazy;
}
} }
public String getLazyGroup() { public String getLazyGroup() {
@ -333,7 +335,7 @@ public class Property implements Serializable, MetaAttributable {
} }
public boolean isOptional() { public boolean isOptional() {
return optional || isNullable(); return optional;
} }
public void setOptional(boolean optional) { public void setOptional(boolean optional) {
@ -361,12 +363,12 @@ public class Property implements Serializable, MetaAttributable {
} }
// todo : remove // todo : remove
public Getter getGetter(Class clazz) throws PropertyNotFoundException, MappingException { public Getter getGetter(Class clazz) throws MappingException {
return getPropertyAccessStrategy( clazz ).buildPropertyAccess( clazz, name, true ).getGetter(); return getPropertyAccessStrategy( clazz ).buildPropertyAccess( clazz, name, true ).getGetter();
} }
// todo : remove // todo : remove
public Setter getSetter(Class clazz) throws PropertyNotFoundException, MappingException { public Setter getSetter(Class clazz) throws MappingException {
return getPropertyAccessStrategy( clazz ).buildPropertyAccess( clazz, name, true ).getSetter(); return getPropertyAccessStrategy( clazz ).buildPropertyAccess( clazz, name, true ).getSetter();
} }
@ -454,27 +456,27 @@ public class Property implements Serializable, MetaAttributable {
} }
public Property copy() { public Property copy() {
final Property prop = new Property(); final Property property = new Property();
prop.setName( getName() ); property.setName( getName() );
prop.setValue( getValue() ); property.setValue( getValue() );
prop.setCascade( getCascade() ); property.setCascade( getCascade() );
prop.setUpdateable( isUpdateable() ); property.setUpdateable( isUpdateable() );
prop.setInsertable( isInsertable() ); property.setInsertable( isInsertable() );
prop.setSelectable( isSelectable() ); property.setSelectable( isSelectable() );
prop.setOptimisticLocked( isOptimisticLocked() ); property.setOptimisticLocked( isOptimisticLocked() );
prop.setValueGeneratorCreator( getValueGeneratorCreator() ); property.setValueGeneratorCreator( getValueGeneratorCreator() );
prop.setPropertyAccessorName( getPropertyAccessorName() ); property.setPropertyAccessorName( getPropertyAccessorName() );
prop.setPropertyAccessStrategy( getPropertyAccessStrategy() ); property.setPropertyAccessStrategy( getPropertyAccessStrategy() );
prop.setLazy( isLazy() ); property.setLazy( isLazy() );
prop.setLazyGroup( getLazyGroup() ); property.setLazyGroup( getLazyGroup() );
prop.setOptional( isOptional() ); property.setOptional( isOptional() );
prop.setMetaAttributes( getMetaAttributes() ); property.setMetaAttributes( getMetaAttributes() );
prop.setPersistentClass( getPersistentClass() ); property.setPersistentClass( getPersistentClass() );
prop.setNaturalIdentifier( isNaturalIdentifier() ); property.setNaturalIdentifier( isNaturalIdentifier() );
prop.setLob( isLob() ); property.setLob( isLob() );
prop.addCallbackDefinitions( getCallbackDefinitions() ); property.addCallbackDefinitions( getCallbackDefinitions() );
prop.setReturnedClassName( getReturnedClassName() ); property.setReturnedClassName( getReturnedClassName() );
return prop; return property;
} }
private class PropertyGeneratorCreationContext implements GeneratorCreationContext { private class PropertyGeneratorCreationContext implements GeneratorCreationContext {

View File

@ -554,7 +554,7 @@ public abstract class AbstractEntityPersister
throw new IllegalArgumentException( "Could not resolve named load-query [" + getEntityName() throw new IllegalArgumentException( "Could not resolve named load-query [" + getEntityName()
+ "] : " + bootDescriptor.getLoaderName() ); + "] : " + bootDescriptor.getLoaderName() );
} }
singleIdEntityLoader = new SingleIdEntityLoaderProvidedQueryImpl<>(this, namedQueryMemento ); singleIdEntityLoader = new SingleIdEntityLoaderProvidedQueryImpl<>( this, namedQueryMemento );
} }
else if ( batchSize > 1 ) { else if ( batchSize > 1 ) {
singleIdEntityLoader = createBatchingIdEntityLoader( this, batchSize, factory ); singleIdEntityLoader = createBatchingIdEntityLoader( this, batchSize, factory );
@ -4723,17 +4723,17 @@ public abstract class AbstractEntityPersister
creationProcess.registerInitializationCallback( creationProcess.registerInitializationCallback(
"Entity(" + getEntityName() + ") `staticFetchableList` generator", "Entity(" + getEntityName() + ") `staticFetchableList` generator",
() -> { () -> {
final ImmutableAttributeMappingList.Builder builder =
new ImmutableAttributeMappingList.Builder( attributeMappings.size() );
visitSubTypeAttributeMappings( builder::add );
assert superMappingType != null || builder.assertFetchableIndexes();
staticFetchableList = builder.build();
if ( hasInsertGeneratedProperties() ) { if ( hasInsertGeneratedProperties() ) {
insertGeneratedValuesProcessor = createGeneratedValuesProcessor( INSERT ); insertGeneratedValuesProcessor = createGeneratedValuesProcessor( INSERT );
} }
if ( hasUpdateGeneratedProperties() ) { if ( hasUpdateGeneratedProperties() ) {
updateGeneratedValuesProcessor = createGeneratedValuesProcessor( UPDATE ); updateGeneratedValuesProcessor = createGeneratedValuesProcessor( UPDATE );
} }
final ImmutableAttributeMappingList.Builder builder =
new ImmutableAttributeMappingList.Builder( attributeMappings.size() );
visitSubTypeAttributeMappings( builder::add );
assert superMappingType != null || builder.assertFetchableIndexes();
staticFetchableList = builder.build();
return true; return true;
} }
); );

View File

@ -21,12 +21,10 @@ import org.hibernate.sql.ast.tree.AbstractStatement;
import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.cte.CteContainer; import org.hibernate.sql.ast.tree.cte.CteContainer;
import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**

View File

@ -10,10 +10,8 @@ import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne; import jakarta.persistence.OneToOne;
import jakarta.persistence.PrimaryKeyJoinColumn; import jakarta.persistence.PrimaryKeyJoinColumn;
import jakarta.persistence.Table; import jakarta.persistence.Table;

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.orm.test.mapping.naturalid.nullable; package org.hibernate.orm.test.mapping.naturalid.nullable;
import jakarta.persistence.Basic;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;