HHH-15831 Support non-basic values in aggregate components
This commit is contained in:
parent
6247dea9a6
commit
ed2fdce0a6
|
@ -407,6 +407,8 @@ public class CockroachLegacyDialect extends Dialect {
|
||||||
.getDescriptor( Object.class )
|
.getDescriptor( Object.class )
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1441,6 +1441,8 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
||||||
.getDescriptor( Object.class )
|
.getDescriptor( Object.class )
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -47,6 +47,16 @@ public @interface Struct {
|
||||||
*/
|
*/
|
||||||
String name();
|
String name();
|
||||||
|
|
||||||
|
/** (Optional) The catalog of the UDT.
|
||||||
|
* <p> Defaults to the default catalog.
|
||||||
|
*/
|
||||||
|
String catalog() default "";
|
||||||
|
|
||||||
|
/** (Optional) The schema of the UDT.
|
||||||
|
* <p> Defaults to the default schema for user.
|
||||||
|
*/
|
||||||
|
String schema() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ordered set of attributes of the UDT, as they appear physically in the DDL.
|
* The ordered set of attributes of the UDT, as they appear physically in the DDL.
|
||||||
* It is important to specify the attributes in the same order for JDBC interactions to work correctly.
|
* It is important to specify the attributes in the same order for JDBC interactions to work correctly.
|
||||||
|
|
|
@ -1778,7 +1778,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
||||||
processSecondPasses( idGeneratorResolverSecondPassList );
|
processSecondPasses( idGeneratorResolverSecondPassList );
|
||||||
processSecondPasses( implicitColumnNamingSecondPassList );
|
processSecondPasses( implicitColumnNamingSecondPassList );
|
||||||
processSecondPasses( setBasicValueTypeSecondPassList );
|
processSecondPasses( setBasicValueTypeSecondPassList );
|
||||||
processSecondPasses( aggregateComponentSecondPassList );
|
|
||||||
processSecondPasses( toOneJoinTableSecondPassList );
|
processSecondPasses( toOneJoinTableSecondPassList );
|
||||||
|
|
||||||
composites.forEach( Component::sortProperties );
|
composites.forEach( Component::sortProperties );
|
||||||
|
@ -1794,6 +1793,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
||||||
|
|
||||||
processPropertyReferences();
|
processPropertyReferences();
|
||||||
|
|
||||||
|
processSecondPasses( aggregateComponentSecondPassList );
|
||||||
secondPassCompileForeignKeys( buildingContext );
|
secondPassCompileForeignKeys( buildingContext );
|
||||||
|
|
||||||
processNaturalIdUniqueKeyBinders();
|
processNaturalIdUniqueKeyBinders();
|
||||||
|
|
|
@ -8,20 +8,20 @@ package org.hibernate.boot.model.internal;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.AnnotationException;
|
|
||||||
import org.hibernate.annotations.JdbcTypeCode;
|
import org.hibernate.annotations.JdbcTypeCode;
|
||||||
import org.hibernate.annotations.Struct;
|
import org.hibernate.annotations.Struct;
|
||||||
import org.hibernate.annotations.common.reflection.XClass;
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
import org.hibernate.annotations.common.reflection.XProperty;
|
import org.hibernate.annotations.common.reflection.XProperty;
|
||||||
|
import org.hibernate.boot.model.relational.Database;
|
||||||
|
import org.hibernate.boot.model.relational.QualifiedName;
|
||||||
|
import org.hibernate.boot.model.relational.QualifiedNameImpl;
|
||||||
|
import org.hibernate.boot.model.relational.QualifiedNameParser;
|
||||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.boot.spi.PropertyData;
|
import org.hibernate.boot.spi.PropertyData;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
|
||||||
import org.hibernate.mapping.AggregateColumn;
|
import org.hibernate.mapping.AggregateColumn;
|
||||||
import org.hibernate.mapping.BasicValue;
|
import org.hibernate.mapping.BasicValue;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.Property;
|
|
||||||
import org.hibernate.mapping.Value;
|
|
||||||
import org.hibernate.type.SqlTypes;
|
import org.hibernate.type.SqlTypes;
|
||||||
import org.hibernate.type.descriptor.java.spi.EmbeddableAggregateJavaType;
|
import org.hibernate.type.descriptor.java.spi.EmbeddableAggregateJavaType;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
@ -42,19 +42,18 @@ public final class AggregateComponentBinder {
|
||||||
AnnotatedColumns columns,
|
AnnotatedColumns columns,
|
||||||
MetadataBuildingContext context) {
|
MetadataBuildingContext context) {
|
||||||
if ( isAggregate( inferredData.getProperty(), componentXClass ) ) {
|
if ( isAggregate( inferredData.getProperty(), componentXClass ) ) {
|
||||||
validateComponent( component, BinderHelper.getPath( propertyHolder, inferredData ) );
|
|
||||||
|
|
||||||
final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
|
final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
|
||||||
final TypeConfiguration typeConfiguration = metadataCollector.getTypeConfiguration();
|
final TypeConfiguration typeConfiguration = metadataCollector.getTypeConfiguration();
|
||||||
// Determine a struct name if this is a struct through some means
|
// Determine a struct name if this is a struct through some means
|
||||||
final String structName = determineStructName( columns, inferredData, componentXClass );
|
final QualifiedName structQualifiedName = determineStructName( columns, inferredData, componentXClass, context );
|
||||||
|
final String structName = structQualifiedName == null ? null : structQualifiedName.render();
|
||||||
|
|
||||||
// We must register a special JavaType for the embeddable which can provide a recommended JdbcType
|
// We must register a special JavaType for the embeddable which can provide a recommended JdbcType
|
||||||
typeConfiguration.getJavaTypeRegistry().resolveDescriptor(
|
typeConfiguration.getJavaTypeRegistry().resolveDescriptor(
|
||||||
component.getComponentClass(),
|
component.getComponentClass(),
|
||||||
() -> new EmbeddableAggregateJavaType<>( component.getComponentClass(), structName )
|
() -> new EmbeddableAggregateJavaType<>( component.getComponentClass(), structName )
|
||||||
);
|
);
|
||||||
component.setStructName( structName );
|
component.setStructName( structQualifiedName );
|
||||||
component.setStructColumnNames( determineStructAttributeNames( inferredData, componentXClass ) );
|
component.setStructColumnNames( determineStructAttributeNames( inferredData, componentXClass ) );
|
||||||
|
|
||||||
// Determine the aggregate column
|
// Determine the aggregate column
|
||||||
|
@ -97,6 +96,7 @@ public final class AggregateComponentBinder {
|
||||||
propertyHolder,
|
propertyHolder,
|
||||||
component,
|
component,
|
||||||
componentXClass,
|
componentXClass,
|
||||||
|
inferredData.getPropertyName(),
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -111,60 +111,59 @@ public final class AggregateComponentBinder {
|
||||||
case SqlTypes.TABLE:
|
case SqlTypes.TABLE:
|
||||||
return SqlTypes.STRUCT_TABLE;
|
return SqlTypes.STRUCT_TABLE;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException( "Unsupported array type code: " + arrayTypeCode );
|
throw new UnsupportedOperationException( "Dialect does not support structured array types: " + context.getMetadataCollector()
|
||||||
|
.getDatabase()
|
||||||
|
.getDialect()
|
||||||
|
.getClass()
|
||||||
|
.getName() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateComponent(Component component, String basePath) {
|
private static QualifiedName determineStructName(
|
||||||
for ( Property property : component.getProperties() ) {
|
|
||||||
final Value value = property.getValue();
|
|
||||||
if ( !( value instanceof BasicValue ) && !( value instanceof Component ) ) {
|
|
||||||
// todo: see HHH-15831
|
|
||||||
throw new AnnotationException(
|
|
||||||
"Property '" + StringHelper.qualify( basePath, property.getName() )
|
|
||||||
+ "' uses not yet supported mapping type '"
|
|
||||||
+ value.getClass().getName()
|
|
||||||
+ "' in component class '"
|
|
||||||
+ component.getComponentClassName()
|
|
||||||
+ "'. Aggregate components currently may only contain basic values and components of basic values."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ( value instanceof Component ) {
|
|
||||||
final Component c = (Component) value;
|
|
||||||
if ( c.getAggregateColumn() == null ) {
|
|
||||||
validateComponent( c, StringHelper.qualify( basePath, property.getName() ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String determineStructName(
|
|
||||||
AnnotatedColumns columns,
|
AnnotatedColumns columns,
|
||||||
PropertyData inferredData,
|
PropertyData inferredData,
|
||||||
XClass returnedClassOrElement) {
|
XClass returnedClassOrElement,
|
||||||
|
MetadataBuildingContext context) {
|
||||||
final XProperty property = inferredData.getProperty();
|
final XProperty property = inferredData.getProperty();
|
||||||
if ( property != null ) {
|
if ( property != null ) {
|
||||||
final Struct struct = property.getAnnotation( Struct.class );
|
final Struct struct = property.getAnnotation( Struct.class );
|
||||||
if ( struct != null ) {
|
if ( struct != null ) {
|
||||||
return struct.name();
|
return toQualifiedName( struct, context );
|
||||||
}
|
}
|
||||||
final JdbcTypeCode jdbcTypeCode = property.getAnnotation( JdbcTypeCode.class );
|
final JdbcTypeCode jdbcTypeCode = property.getAnnotation( JdbcTypeCode.class );
|
||||||
if ( jdbcTypeCode != null
|
if ( jdbcTypeCode != null
|
||||||
&& ( jdbcTypeCode.value() == SqlTypes.STRUCT || jdbcTypeCode.value() == SqlTypes.STRUCT_ARRAY || jdbcTypeCode.value() == SqlTypes.STRUCT_TABLE )
|
&& ( jdbcTypeCode.value() == SqlTypes.STRUCT || jdbcTypeCode.value() == SqlTypes.STRUCT_ARRAY || jdbcTypeCode.value() == SqlTypes.STRUCT_TABLE )
|
||||||
&& columns != null ) {
|
&& columns != null ) {
|
||||||
final List<AnnotatedColumn> columnList = columns.getColumns();
|
final List<AnnotatedColumn> columnList = columns.getColumns();
|
||||||
if ( columnList.size() == 1 && columnList.get( 0 ).getSqlType() != null ) {
|
final String sqlType;
|
||||||
return columnList.get( 0 ).getSqlType();
|
if ( columnList.size() == 1 && ( sqlType = columnList.get( 0 ).getSqlType() ) != null ) {
|
||||||
|
if ( sqlType.contains( "." ) ) {
|
||||||
|
return QualifiedNameParser.INSTANCE.parse( sqlType );
|
||||||
|
}
|
||||||
|
return new QualifiedNameParser.NameParts(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
context.getMetadataCollector().getDatabase().toIdentifier( sqlType )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Struct struct = returnedClassOrElement.getAnnotation( Struct.class );
|
final Struct struct = returnedClassOrElement.getAnnotation( Struct.class );
|
||||||
if ( struct != null ) {
|
if ( struct != null ) {
|
||||||
return struct.name();
|
return toQualifiedName( struct, context );
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static QualifiedName toQualifiedName(Struct struct, MetadataBuildingContext context) {
|
||||||
|
final Database database = context.getMetadataCollector().getDatabase();
|
||||||
|
return new QualifiedNameImpl(
|
||||||
|
database.toIdentifier( struct.catalog() ),
|
||||||
|
database.toIdentifier( struct.schema() ),
|
||||||
|
database.toIdentifier( struct.name() )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static String[] determineStructAttributeNames(PropertyData inferredData, XClass returnedClassOrElement) {
|
private static String[] determineStructAttributeNames(PropertyData inferredData, XClass returnedClassOrElement) {
|
||||||
final XProperty property = inferredData.getProperty();
|
final XProperty property = inferredData.getProperty();
|
||||||
if ( property != null ) {
|
if ( property != null ) {
|
||||||
|
|
|
@ -11,25 +11,27 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.annotations.Comment;
|
import org.hibernate.annotations.Comment;
|
||||||
import org.hibernate.annotations.common.reflection.XClass;
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
import org.hibernate.boot.model.naming.Identifier;
|
|
||||||
import org.hibernate.boot.model.relational.Database;
|
import org.hibernate.boot.model.relational.Database;
|
||||||
import org.hibernate.boot.model.relational.Namespace;
|
import org.hibernate.boot.model.relational.Namespace;
|
||||||
|
import org.hibernate.boot.model.relational.QualifiedName;
|
||||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.boot.spi.SecondPass;
|
import org.hibernate.boot.spi.SecondPass;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.dialect.aggregate.AggregateSupport;
|
import org.hibernate.dialect.aggregate.AggregateSupport;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
|
||||||
import org.hibernate.mapping.AggregateColumn;
|
import org.hibernate.mapping.AggregateColumn;
|
||||||
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.Column;
|
import org.hibernate.mapping.Column;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.mapping.Selectable;
|
import org.hibernate.mapping.Selectable;
|
||||||
|
import org.hibernate.mapping.ToOne;
|
||||||
import org.hibernate.mapping.UserDefinedObjectType;
|
import org.hibernate.mapping.UserDefinedObjectType;
|
||||||
import org.hibernate.mapping.Value;
|
import org.hibernate.mapping.Value;
|
||||||
import org.hibernate.metamodel.internal.EmbeddableHelper;
|
import org.hibernate.metamodel.internal.EmbeddableHelper;
|
||||||
|
@ -37,6 +39,8 @@ import org.hibernate.sql.Template;
|
||||||
import org.hibernate.type.SqlTypes;
|
import org.hibernate.type.SqlTypes;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christian Beikov
|
* @author Christian Beikov
|
||||||
*/
|
*/
|
||||||
|
@ -45,20 +49,26 @@ public class AggregateComponentSecondPass implements SecondPass {
|
||||||
private final PropertyHolder propertyHolder;
|
private final PropertyHolder propertyHolder;
|
||||||
private final Component component;
|
private final Component component;
|
||||||
private final XClass componentXClass;
|
private final XClass componentXClass;
|
||||||
|
private final String propertyName;
|
||||||
private final MetadataBuildingContext context;
|
private final MetadataBuildingContext context;
|
||||||
|
|
||||||
public AggregateComponentSecondPass(
|
public AggregateComponentSecondPass(
|
||||||
PropertyHolder propertyHolder,
|
PropertyHolder propertyHolder,
|
||||||
Component component,
|
Component component,
|
||||||
XClass componentXClass,
|
XClass componentXClass,
|
||||||
|
String propertyName,
|
||||||
MetadataBuildingContext context) {
|
MetadataBuildingContext context) {
|
||||||
this.propertyHolder = propertyHolder;
|
this.propertyHolder = propertyHolder;
|
||||||
this.component = component;
|
this.component = component;
|
||||||
this.componentXClass = componentXClass;
|
this.componentXClass = componentXClass;
|
||||||
|
this.propertyName = propertyName;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||||
|
validateComponent( component, qualify( propertyHolder.getPath(), propertyName ), isAggregateArray() );
|
||||||
|
|
||||||
final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
|
final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
|
||||||
final TypeConfiguration typeConfiguration = metadataCollector.getTypeConfiguration();
|
final TypeConfiguration typeConfiguration = metadataCollector.getTypeConfiguration();
|
||||||
final Database database = metadataCollector.getDatabase();
|
final Database database = metadataCollector.getDatabase();
|
||||||
|
@ -72,21 +82,17 @@ public class AggregateComponentSecondPass implements SecondPass {
|
||||||
final List<Column> aggregatedColumns = component.getAggregatedColumns();
|
final List<Column> aggregatedColumns = component.getAggregatedColumns();
|
||||||
final AggregateColumn aggregateColumn = component.getAggregateColumn();
|
final AggregateColumn aggregateColumn = component.getAggregateColumn();
|
||||||
|
|
||||||
ensureInitialized( metadataCollector, typeConfiguration, dialect, aggregateColumn );
|
ensureInitialized( metadataCollector, aggregateColumn );
|
||||||
validateSupportedColumnTypes( propertyHolder.getPath(), component );
|
validateSupportedColumnTypes( propertyHolder.getPath(), component );
|
||||||
|
|
||||||
for ( org.hibernate.mapping.Column aggregatedColumn : aggregatedColumns ) {
|
final QualifiedName structName = component.getStructName();
|
||||||
// Make sure this state is initialized
|
|
||||||
aggregatedColumn.getSqlTypeCode( metadataCollector );
|
|
||||||
aggregatedColumn.getSqlType( metadataCollector );
|
|
||||||
}
|
|
||||||
|
|
||||||
final String structName = component.getStructName();
|
|
||||||
final boolean addAuxiliaryObjects;
|
final boolean addAuxiliaryObjects;
|
||||||
if ( structName != null ) {
|
if ( structName != null ) {
|
||||||
final Namespace defaultNamespace = database.getDefaultNamespace();
|
final Namespace namespace = database.locateNamespace(
|
||||||
final Identifier udtName = Identifier.toIdentifier( structName );
|
structName.getCatalogName(),
|
||||||
final UserDefinedObjectType udt = new UserDefinedObjectType( "orm", defaultNamespace, udtName );
|
structName.getSchemaName()
|
||||||
|
);
|
||||||
|
final UserDefinedObjectType udt = new UserDefinedObjectType( "orm", namespace, structName.getObjectName() );
|
||||||
final Comment comment = componentXClass.getAnnotation( Comment.class );
|
final Comment comment = componentXClass.getAnnotation( Comment.class );
|
||||||
if ( comment != null ) {
|
if ( comment != null ) {
|
||||||
udt.setComment( comment.value() );
|
udt.setComment( comment.value() );
|
||||||
|
@ -94,8 +100,8 @@ public class AggregateComponentSecondPass implements SecondPass {
|
||||||
for ( org.hibernate.mapping.Column aggregatedColumn : aggregatedColumns ) {
|
for ( org.hibernate.mapping.Column aggregatedColumn : aggregatedColumns ) {
|
||||||
udt.addColumn( aggregatedColumn );
|
udt.addColumn( aggregatedColumn );
|
||||||
}
|
}
|
||||||
final UserDefinedObjectType registeredUdt = defaultNamespace.createUserDefinedType(
|
final UserDefinedObjectType registeredUdt = namespace.createUserDefinedType(
|
||||||
udtName,
|
structName.getObjectName(),
|
||||||
name -> udt
|
name -> udt
|
||||||
);
|
);
|
||||||
if ( registeredUdt == udt ) {
|
if ( registeredUdt == udt ) {
|
||||||
|
@ -187,6 +193,66 @@ public class AggregateComponentSecondPass implements SecondPass {
|
||||||
propertyHolder.getTable().getColumns().removeAll( aggregatedColumns );
|
propertyHolder.getTable().getColumns().removeAll( aggregatedColumns );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void validateComponent(Component component, String basePath, boolean inArray) {
|
||||||
|
for ( Property property : component.getProperties() ) {
|
||||||
|
final Value value = property.getValue();
|
||||||
|
if ( value instanceof Component ) {
|
||||||
|
final Component c = (Component) value;
|
||||||
|
validateComponent( c, qualify( basePath, property.getName() ), inArray );
|
||||||
|
}
|
||||||
|
else if ( value instanceof ToOne ) {
|
||||||
|
final ToOne toOne = (ToOne) value;
|
||||||
|
if ( inArray && toOne.getReferencedPropertyName() != null ) {
|
||||||
|
throw new AnnotationException(
|
||||||
|
"Property '" + qualify( basePath, property.getName() )
|
||||||
|
+ "' uses one-to-one mapping with mappedBy '"
|
||||||
|
+ toOne.getReferencedPropertyName()
|
||||||
|
+ "' in the aggregate component class '"
|
||||||
|
+ component.getComponentClassName()
|
||||||
|
+ "' within an array property, which is not allowed."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( value instanceof Collection ) {
|
||||||
|
final Collection collection = (Collection) value;
|
||||||
|
if ( inArray && collection.getMappedByProperty() != null ) {
|
||||||
|
throw new AnnotationException(
|
||||||
|
"Property '" + qualify( basePath, property.getName() )
|
||||||
|
+ "' uses *-to-many mapping with mappedBy '"
|
||||||
|
+ collection.getMappedByProperty()
|
||||||
|
+ "' in the aggregate component class '"
|
||||||
|
+ component.getComponentClassName()
|
||||||
|
+ "' within an array property, which is not allowed."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( inArray && collection.getCollectionTable() != null ) {
|
||||||
|
throw new AnnotationException(
|
||||||
|
"Property '" + qualify( basePath, property.getName() )
|
||||||
|
+ "' defines a collection table '"
|
||||||
|
+ collection.getCollectionTable()
|
||||||
|
+ "' in the aggregate component class '"
|
||||||
|
+ component.getComponentClassName()
|
||||||
|
+ "' within an array property, which is not allowed."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAggregateArray() {
|
||||||
|
switch ( component.getAggregateColumn().getSqlTypeCode( context.getMetadataCollector() ) ) {
|
||||||
|
case SqlTypes.STRUCT_ARRAY:
|
||||||
|
case SqlTypes.STRUCT_TABLE:
|
||||||
|
case SqlTypes.JSON_ARRAY:
|
||||||
|
case SqlTypes.XML_ARRAY:
|
||||||
|
case SqlTypes.ARRAY:
|
||||||
|
case SqlTypes.TABLE:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void orderColumns(UserDefinedObjectType userDefinedType, int[] originalOrder) {
|
private void orderColumns(UserDefinedObjectType userDefinedType, int[] originalOrder) {
|
||||||
final Class<?> componentClass = component.getComponentClass();
|
final Class<?> componentClass = component.getComponentClass();
|
||||||
final String[] structColumnNames = component.getStructColumnNames();
|
final String[] structColumnNames = component.getStructColumnNames();
|
||||||
|
@ -303,7 +369,7 @@ public class AggregateComponentSecondPass implements SecondPass {
|
||||||
if ( value instanceof Component ) {
|
if ( value instanceof Component ) {
|
||||||
final Component subComponent = (Component) value;
|
final Component subComponent = (Component) value;
|
||||||
if ( subComponent.getAggregateColumn() == null ) {
|
if ( subComponent.getAggregateColumn() == null ) {
|
||||||
validateSupportedColumnTypes( StringHelper.qualify( basePath, property.getName() ), subComponent );
|
validateSupportedColumnTypes( qualify( basePath, property.getName() ), subComponent );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,8 +377,27 @@ public class AggregateComponentSecondPass implements SecondPass {
|
||||||
|
|
||||||
private static void ensureInitialized(
|
private static void ensureInitialized(
|
||||||
InFlightMetadataCollector metadataCollector,
|
InFlightMetadataCollector metadataCollector,
|
||||||
TypeConfiguration typeConfiguration,
|
AggregateColumn aggregateColumn) {
|
||||||
Dialect dialect,
|
ensureParentInitialized( metadataCollector, aggregateColumn );
|
||||||
|
ensureChildrenInitialized( metadataCollector, aggregateColumn );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureChildrenInitialized(
|
||||||
|
InFlightMetadataCollector metadataCollector,
|
||||||
|
AggregateColumn aggregateColumn) {
|
||||||
|
for ( Column aggregatedColumn : aggregateColumn.getComponent().getAggregatedColumns() ) {
|
||||||
|
// Make sure this state is initialized
|
||||||
|
aggregatedColumn.getSqlTypeCode( metadataCollector );
|
||||||
|
aggregatedColumn.getSqlType( metadataCollector );
|
||||||
|
if ( aggregatedColumn instanceof AggregateColumn ) {
|
||||||
|
ensureChildrenInitialized( metadataCollector, (AggregateColumn) aggregatedColumn );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureParentInitialized(
|
||||||
|
InFlightMetadataCollector metadataCollector,
|
||||||
AggregateColumn aggregateColumn) {
|
AggregateColumn aggregateColumn) {
|
||||||
do {
|
do {
|
||||||
// Trigger resolving of the value so that the column gets properly filled
|
// Trigger resolving of the value so that the column gets properly filled
|
||||||
|
|
|
@ -1224,6 +1224,11 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
||||||
|
|
||||||
basicValue = new BasicValue( buildingContext, table );
|
basicValue = new BasicValue( buildingContext, table );
|
||||||
|
|
||||||
|
if ( columns.getPropertyHolder().isComponent() ) {
|
||||||
|
final ComponentPropertyHolder propertyHolder = (ComponentPropertyHolder) columns.getPropertyHolder();
|
||||||
|
basicValue.setAggregateColumn( propertyHolder.getAggregateColumn() );
|
||||||
|
}
|
||||||
|
|
||||||
if ( isNationalized() ) {
|
if ( isNationalized() ) {
|
||||||
basicValue.makeNationalized();
|
basicValue.makeNationalized();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.hibernate.annotations.common.reflection.XClass;
|
||||||
import org.hibernate.annotations.common.reflection.XProperty;
|
import org.hibernate.annotations.common.reflection.XProperty;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.boot.spi.PropertyData;
|
import org.hibernate.boot.spi.PropertyData;
|
||||||
|
import org.hibernate.mapping.AggregateColumn;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.Join;
|
import org.hibernate.mapping.Join;
|
||||||
import org.hibernate.mapping.KeyValue;
|
import org.hibernate.mapping.KeyValue;
|
||||||
|
@ -265,7 +266,7 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
|
||||||
// if a property is set already the core cannot support that
|
// if a property is set already the core cannot support that
|
||||||
if ( columns != null ) {
|
if ( columns != null ) {
|
||||||
final Table table = columns.getTable();
|
final Table table = columns.getTable();
|
||||||
if ( !table.equals( component.getTable() ) ) {
|
if ( !table.equals( getTable() ) ) {
|
||||||
if ( component.getPropertySpan() == 0 ) {
|
if ( component.getPropertySpan() == 0 ) {
|
||||||
component.setTable( table );
|
component.setTable( table );
|
||||||
}
|
}
|
||||||
|
@ -301,6 +302,11 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
|
||||||
return component.getOwner().getClassName();
|
return component.getOwner().getClassName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AggregateColumn getAggregateColumn() {
|
||||||
|
final AggregateColumn aggregateColumn = component.getAggregateColumn();
|
||||||
|
return aggregateColumn != null ? aggregateColumn : component.getParentAggregateColumn();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Table getTable() {
|
public Table getTable() {
|
||||||
return component.getTable();
|
return component.getTable();
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.hibernate.boot.spi.AccessType;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.boot.spi.PropertyData;
|
import org.hibernate.boot.spi.PropertyData;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
|
import org.hibernate.mapping.AggregateColumn;
|
||||||
import org.hibernate.mapping.BasicValue;
|
import org.hibernate.mapping.BasicValue;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
|
@ -371,6 +372,14 @@ public class EmbeddableBinder {
|
||||||
returnedClassOrElement = context.getBootstrapContext().getReflectionManager()
|
returnedClassOrElement = context.getBootstrapContext().getReflectionManager()
|
||||||
.toXClass( compositeUserType.embeddable() );
|
.toXClass( compositeUserType.embeddable() );
|
||||||
}
|
}
|
||||||
|
AggregateComponentBinder.processAggregate(
|
||||||
|
component,
|
||||||
|
propertyHolder,
|
||||||
|
inferredData,
|
||||||
|
returnedClassOrElement,
|
||||||
|
columns,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
final XClass annotatedClass = inferredData.getPropertyClass();
|
final XClass annotatedClass = inferredData.getPropertyClass();
|
||||||
final List<PropertyData> classElements =
|
final List<PropertyData> classElements =
|
||||||
|
@ -447,14 +456,6 @@ public class EmbeddableBinder {
|
||||||
processCompositeUserType( component, compositeUserType );
|
processCompositeUserType( component, compositeUserType );
|
||||||
}
|
}
|
||||||
|
|
||||||
AggregateComponentBinder.processAggregate(
|
|
||||||
component,
|
|
||||||
propertyHolder,
|
|
||||||
inferredData,
|
|
||||||
returnedClassOrElement,
|
|
||||||
columns,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,6 +564,7 @@ public class EmbeddableBinder {
|
||||||
columns.setBuildingContext( context );
|
columns.setBuildingContext( context );
|
||||||
discriminatorColumn.setParent( columns );
|
discriminatorColumn.setParent( columns );
|
||||||
final BasicValue discriminatorColumnBinding = new BasicValue( context, component.getTable() );
|
final BasicValue discriminatorColumnBinding = new BasicValue( context, component.getTable() );
|
||||||
|
discriminatorColumnBinding.setAggregateColumn( component.getAggregateColumn() );
|
||||||
component.setDiscriminator( discriminatorColumnBinding );
|
component.setDiscriminator( discriminatorColumnBinding );
|
||||||
discriminatorColumn.linkWithValue( discriminatorColumnBinding );
|
discriminatorColumn.linkWithValue( discriminatorColumnBinding );
|
||||||
discriminatorColumnBinding.setTypeName( discriminatorColumn.getDiscriminatorTypeName() );
|
discriminatorColumnBinding.setTypeName( discriminatorColumn.getDiscriminatorTypeName() );
|
||||||
|
@ -858,6 +860,10 @@ public class EmbeddableBinder {
|
||||||
if ( constructor != null ) {
|
if ( constructor != null ) {
|
||||||
component.setInstantiator( constructor, constructor.getAnnotation( Instantiator.class ).value() );
|
component.setInstantiator( constructor, constructor.getAnnotation( Instantiator.class ).value() );
|
||||||
}
|
}
|
||||||
|
if ( propertyHolder.isComponent() ) {
|
||||||
|
final ComponentPropertyHolder componentPropertyHolder = (ComponentPropertyHolder) propertyHolder;
|
||||||
|
component.setParentAggregateColumn( componentPropertyHolder.getAggregateColumn() );
|
||||||
|
}
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.hibernate.mapping.UserDefinedArrayType;
|
||||||
import org.hibernate.mapping.UserDefinedObjectType;
|
import org.hibernate.mapping.UserDefinedObjectType;
|
||||||
import org.hibernate.mapping.UserDefinedType;
|
import org.hibernate.mapping.UserDefinedType;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
|
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.SqlTypedJdbcType;
|
import org.hibernate.type.descriptor.jdbc.SqlTypedJdbcType;
|
||||||
|
@ -183,14 +184,17 @@ public class Namespace {
|
||||||
final UserDefinedType udt = entry.getValue();
|
final UserDefinedType udt = entry.getValue();
|
||||||
if ( udt instanceof UserDefinedObjectType ) {
|
if ( udt instanceof UserDefinedObjectType ) {
|
||||||
for ( Column udtColumn : ( (UserDefinedObjectType) udt ).getColumns() ) {
|
for ( Column udtColumn : ( (UserDefinedObjectType) udt ).getColumns() ) {
|
||||||
final JdbcType jdbcType = ( (BasicType<?>) udtColumn.getValue().getType() ).getJdbcType();
|
final Type udtColumnType = udtColumn.getValue().getType();
|
||||||
if ( jdbcType instanceof SqlTypedJdbcType ) {
|
if ( udtColumnType instanceof BasicType<?> ) {
|
||||||
dependencies.add( Identifier.toIdentifier( ( (SqlTypedJdbcType) jdbcType ).getSqlTypeName() ) );
|
final JdbcType jdbcType = ( (BasicType<?>) udtColumnType ).getJdbcType();
|
||||||
}
|
if ( jdbcType instanceof SqlTypedJdbcType ) {
|
||||||
else if ( jdbcType instanceof ArrayJdbcType ) {
|
dependencies.add( Identifier.toIdentifier( ( (SqlTypedJdbcType) jdbcType ).getSqlTypeName() ) );
|
||||||
final JdbcType elementJdbcType = ( (ArrayJdbcType) jdbcType ).getElementJdbcType();
|
}
|
||||||
if ( elementJdbcType instanceof SqlTypedJdbcType ) {
|
else if ( jdbcType instanceof ArrayJdbcType ) {
|
||||||
dependencies.add( Identifier.toIdentifier( ( (SqlTypedJdbcType) elementJdbcType ).getSqlTypeName() ) );
|
final JdbcType elementJdbcType = ( (ArrayJdbcType) jdbcType ).getElementJdbcType();
|
||||||
|
if ( elementJdbcType instanceof SqlTypedJdbcType ) {
|
||||||
|
dependencies.add( Identifier.toIdentifier( ( (SqlTypedJdbcType) elementJdbcType ).getSqlTypeName() ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,11 @@ import java.util.ArrayList;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import org.hibernate.internal.util.CharSequenceHelper;
|
import org.hibernate.internal.util.CharSequenceHelper;
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
|
||||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
|
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
|
||||||
import org.hibernate.type.BasicPluralType;
|
import org.hibernate.type.BasicPluralType;
|
||||||
|
@ -1008,7 +1006,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
||||||
final int size = numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
|
final int size = numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for ( int i = 0; i < size; i++ ) {
|
for ( int i = 0; i < size; i++ ) {
|
||||||
final ValuedModelPart modelPart = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, orderMapping[i] );
|
final ValuedModelPart modelPart = getEmbeddedPart( embeddableMappingType, orderMapping[i] );
|
||||||
final MappingType mappedType = modelPart.getMappedType();
|
final MappingType mappedType = modelPart.getMappedType();
|
||||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
if ( mappedType instanceof EmbeddableMappingType ) {
|
||||||
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
|
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
|
||||||
|
@ -1178,7 +1176,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
||||||
return rawJdbcValue.toString();
|
return rawJdbcValue.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <X> String toString(X value, JavaType<X> javaType, WrapperOptions options) {
|
protected <X> String toString(X value, JavaType<X> javaType, WrapperOptions options) throws SQLException {
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1187,86 +1185,62 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void serializeStructTo(PostgreSQLAppender appender, Object value, WrapperOptions options) {
|
private void serializeStructTo(PostgreSQLAppender appender, Object value, WrapperOptions options) throws SQLException {
|
||||||
serializeValuesTo( appender, options, embeddableMappingType, value, '(' );
|
serializeDomainValueTo( appender, options, value, '(' );
|
||||||
appender.append( ')' );
|
appender.append( ')' );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void serializeValuesTo(
|
private void serializeDomainValueTo(
|
||||||
PostgreSQLAppender appender,
|
PostgreSQLAppender appender,
|
||||||
WrapperOptions options,
|
WrapperOptions options,
|
||||||
EmbeddableMappingType embeddableMappingType,
|
|
||||||
Object domainValue,
|
Object domainValue,
|
||||||
char separator) {
|
char separator) throws SQLException {
|
||||||
final Object[] array = embeddableMappingType.getValues( domainValue );
|
serializeJdbcValuesTo(
|
||||||
final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
|
appender,
|
||||||
for ( int i = 0; i < array.length; i++ ) {
|
options,
|
||||||
final ValuedModelPart attributeMapping;
|
StructHelper.getJdbcValues( embeddableMappingType, orderMapping, domainValue, options ),
|
||||||
final Object attributeValue;
|
separator
|
||||||
if ( orderMapping == null ) {
|
);
|
||||||
attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributes, i );
|
|
||||||
attributeValue = array[i];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributes, orderMapping[i] );
|
|
||||||
attributeValue = array[orderMapping[i]];
|
|
||||||
}
|
|
||||||
if ( attributeMapping instanceof BasicValuedMapping ) {
|
|
||||||
appender.append( separator );
|
|
||||||
separator = ',';
|
|
||||||
if ( attributeValue == null ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final JdbcMapping jdbcMapping = ( (BasicValuedMapping) attributeMapping ).getJdbcMapping();
|
|
||||||
serializeBasicTo( appender, options, jdbcMapping, attributeValue );
|
|
||||||
}
|
|
||||||
else if ( attributeMapping instanceof EmbeddedAttributeMapping ) {
|
|
||||||
final EmbeddableMappingType mappingType = (EmbeddableMappingType) attributeMapping.getMappedType();
|
|
||||||
final SelectableMapping aggregateMapping = mappingType.getAggregateMapping();
|
|
||||||
if ( aggregateMapping == null ) {
|
|
||||||
serializeValuesTo(
|
|
||||||
appender,
|
|
||||||
options,
|
|
||||||
mappingType,
|
|
||||||
attributeValue,
|
|
||||||
separator
|
|
||||||
);
|
|
||||||
separator = ',';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
appender.append( separator );
|
|
||||||
separator = ',';
|
|
||||||
if ( attributeValue == null ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
appender.quoteStart();
|
|
||||||
( (AbstractPostgreSQLStructJdbcType) aggregateMapping.getJdbcMapping().getJdbcType() ).serializeStructTo(
|
|
||||||
appender,
|
|
||||||
attributeValue,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
appender.quoteEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new UnsupportedOperationException( "Unsupported attribute mapping: " + attributeMapping );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void serializeBasicTo(
|
private void serializeJdbcValuesTo(
|
||||||
PostgreSQLAppender appender,
|
PostgreSQLAppender appender,
|
||||||
WrapperOptions options,
|
WrapperOptions options,
|
||||||
JdbcMapping jdbcMapping,
|
Object[] jdbcValues,
|
||||||
Object value) {
|
char separator) throws SQLException {
|
||||||
serializeConvertedBasicTo( appender, options, jdbcMapping, jdbcMapping.convertToRelationalValue( value ) );
|
for ( int i = 0; i < jdbcValues.length; i++ ) {
|
||||||
|
appender.append( separator );
|
||||||
|
separator = ',';
|
||||||
|
final Object jdbcValue = jdbcValues[i];
|
||||||
|
if ( jdbcValue == null ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final SelectableMapping selectableMapping = orderMapping == null ?
|
||||||
|
embeddableMappingType.getJdbcValueSelectable( i ) :
|
||||||
|
embeddableMappingType.getJdbcValueSelectable( orderMapping[i] );
|
||||||
|
final JdbcMapping jdbcMapping = selectableMapping.getJdbcMapping();
|
||||||
|
if ( jdbcMapping.getJdbcType() instanceof AbstractPostgreSQLStructJdbcType ) {
|
||||||
|
appender.quoteStart();
|
||||||
|
( (AbstractPostgreSQLStructJdbcType) jdbcMapping.getJdbcType() ).serializeJdbcValuesTo(
|
||||||
|
appender,
|
||||||
|
options,
|
||||||
|
(Object[]) jdbcValue,
|
||||||
|
'('
|
||||||
|
);
|
||||||
|
appender.append( ')' );
|
||||||
|
appender.quoteEnd();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
serializeConvertedBasicTo( appender, options, jdbcMapping, jdbcValue );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void serializeConvertedBasicTo(
|
private void serializeConvertedBasicTo(
|
||||||
PostgreSQLAppender appender,
|
PostgreSQLAppender appender,
|
||||||
WrapperOptions options,
|
WrapperOptions options,
|
||||||
JdbcMapping jdbcMapping,
|
JdbcMapping jdbcMapping,
|
||||||
Object subValue) {
|
Object subValue) throws SQLException {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
final JavaType<Object> jdbcJavaType = (JavaType<Object>) jdbcMapping.getJdbcJavaType();
|
final JavaType<Object> jdbcJavaType = (JavaType<Object>) jdbcMapping.getJdbcJavaType();
|
||||||
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
|
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
|
||||||
|
@ -1291,14 +1265,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
||||||
case SqlTypes.DECIMAL:
|
case SqlTypes.DECIMAL:
|
||||||
case SqlTypes.NUMERIC:
|
case SqlTypes.NUMERIC:
|
||||||
case SqlTypes.DURATION:
|
case SqlTypes.DURATION:
|
||||||
jdbcJavaType.appendEncodedString(
|
appender.append( subValue.toString() );
|
||||||
appender,
|
|
||||||
jdbcJavaType.unwrap(
|
|
||||||
subValue,
|
|
||||||
jdbcJavaType.getJavaTypeClass(),
|
|
||||||
options
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case SqlTypes.CHAR:
|
case SqlTypes.CHAR:
|
||||||
case SqlTypes.NCHAR:
|
case SqlTypes.NCHAR:
|
||||||
|
@ -1316,14 +1283,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
||||||
case SqlTypes.ENUM:
|
case SqlTypes.ENUM:
|
||||||
case SqlTypes.NAMED_ENUM:
|
case SqlTypes.NAMED_ENUM:
|
||||||
appender.quoteStart();
|
appender.quoteStart();
|
||||||
jdbcJavaType.appendEncodedString(
|
appender.append( (String) subValue );
|
||||||
appender,
|
|
||||||
jdbcJavaType.unwrap(
|
|
||||||
subValue,
|
|
||||||
jdbcJavaType.getJavaTypeClass(),
|
|
||||||
options
|
|
||||||
)
|
|
||||||
);
|
|
||||||
appender.quoteEnd();
|
appender.quoteEnd();
|
||||||
break;
|
break;
|
||||||
case SqlTypes.DATE:
|
case SqlTypes.DATE:
|
||||||
|
@ -1393,9 +1353,8 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
||||||
case SqlTypes.STRUCT:
|
case SqlTypes.STRUCT:
|
||||||
if ( subValue != null ) {
|
if ( subValue != null ) {
|
||||||
final AbstractPostgreSQLStructJdbcType structJdbcType = (AbstractPostgreSQLStructJdbcType) jdbcMapping.getJdbcType();
|
final AbstractPostgreSQLStructJdbcType structJdbcType = (AbstractPostgreSQLStructJdbcType) jdbcMapping.getJdbcType();
|
||||||
final EmbeddableMappingType subEmbeddableMappingType = structJdbcType.getEmbeddableMappingType();
|
|
||||||
appender.quoteStart();
|
appender.quoteStart();
|
||||||
structJdbcType.serializeValuesTo( appender, options, subEmbeddableMappingType, subValue, '(' );
|
structJdbcType.serializeJdbcValuesTo( appender, options, (Object[]) subValue, '(' );
|
||||||
appender.append( ')' );
|
appender.append( ')' );
|
||||||
appender.quoteEnd();
|
appender.quoteEnd();
|
||||||
}
|
}
|
||||||
|
@ -1427,9 +1386,8 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
||||||
else {
|
else {
|
||||||
attributeIndex = orderMapping[i];
|
attributeIndex = orderMapping[i];
|
||||||
}
|
}
|
||||||
final ValuedModelPart modelPart = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, attributeIndex );
|
|
||||||
jdbcIndex += injectAttributeValue(
|
jdbcIndex += injectAttributeValue(
|
||||||
modelPart,
|
getEmbeddedPart( embeddableMappingType, attributeIndex ),
|
||||||
attributeValues,
|
attributeValues,
|
||||||
attributeIndex,
|
attributeIndex,
|
||||||
rawJdbcValues,
|
rawJdbcValues,
|
||||||
|
@ -1567,6 +1525,10 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
||||||
: options.getJdbcTimeZone();
|
: options.getJdbcTimeZone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected <X> Object getBindValue(X value, WrapperOptions options) throws SQLException {
|
||||||
|
return StructHelper.getJdbcValues( embeddableMappingType, orderMapping, value, options );
|
||||||
|
}
|
||||||
|
|
||||||
private static class PostgreSQLAppender extends StringBuilderSqlAppender {
|
private static class PostgreSQLAppender extends StringBuilderSqlAppender {
|
||||||
|
|
||||||
private int quote = 1;
|
private int quote = 1;
|
||||||
|
|
|
@ -410,6 +410,8 @@ public class CockroachDialect extends Dialect {
|
||||||
.getDescriptor( Object.class )
|
.getDescriptor( Object.class )
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class JsonHelper {
|
||||||
final Object[] values = embeddableMappingType.getValues( domainValue );
|
final Object[] values = embeddableMappingType.getValues( domainValue );
|
||||||
final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
|
final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
|
||||||
for ( int i = 0; i < values.length; i++ ) {
|
for ( int i = 0; i < values.length; i++ ) {
|
||||||
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributes, i );
|
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, i );
|
||||||
if ( attributeMapping instanceof SelectableMapping ) {
|
if ( attributeMapping instanceof SelectableMapping ) {
|
||||||
final String name = ( (SelectableMapping) attributeMapping ).getSelectableName();
|
final String name = ( (SelectableMapping) attributeMapping ).getSelectableName();
|
||||||
appender.append( separator );
|
appender.append( separator );
|
||||||
|
|
|
@ -69,6 +69,8 @@ public class OracleArrayJdbcType extends ArrayJdbcType implements SqlTypedJdbcTy
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) {
|
public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) {
|
||||||
|
//noinspection unchecked
|
||||||
|
final ValueBinder<Object> elementBinder = getElementJdbcType().getBinder( ( (BasicPluralJavaType<Object>) javaTypeDescriptor ).getElementJavaType() );
|
||||||
return new BasicBinder<>( javaTypeDescriptor, this ) {
|
return new BasicBinder<>( javaTypeDescriptor, this ) {
|
||||||
private String typeName(WrapperOptions options) {
|
private String typeName(WrapperOptions options) {
|
||||||
return ( upperTypeName == null
|
return ( upperTypeName == null
|
||||||
|
@ -105,7 +107,7 @@ public class OracleArrayJdbcType extends ArrayJdbcType implements SqlTypedJdbcTy
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public java.sql.Array getBindValue(X value, WrapperOptions options) throws SQLException {
|
public java.sql.Array getBindValue(X value, WrapperOptions options) throws SQLException {
|
||||||
final Object[] objects = OracleArrayJdbcType.this.getArray( this, value, options );
|
final Object[] objects = ( (OracleArrayJdbcType) getJdbcType() ).getArray( this, elementBinder, value, options );
|
||||||
final String arrayTypeName = typeName( options );
|
final String arrayTypeName = typeName( options );
|
||||||
|
|
||||||
final OracleConnection oracleConnection = options.getSession()
|
final OracleConnection oracleConnection = options.getSession()
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.dialect;
|
package org.hibernate.dialect;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
@ -17,9 +20,12 @@ import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.type.descriptor.ValueBinder;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||||
|
|
||||||
import oracle.sql.TIMESTAMPTZ;
|
import oracle.sql.TIMESTAMPTZ;
|
||||||
|
|
||||||
|
@ -41,6 +47,28 @@ public class OracleBaseStructJdbcType extends StructJdbcType {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> ValueBinder<X> getBinder(JavaType<X> javaType) {
|
||||||
|
return new BasicBinder<>( javaType, this ) {
|
||||||
|
@Override
|
||||||
|
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||||
|
throws SQLException {
|
||||||
|
st.setObject( index, createJdbcValue( value, options ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||||
|
throws SQLException {
|
||||||
|
st.setObject( name, createJdbcValue( value, options ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBindValue(X value, WrapperOptions options) throws SQLException {
|
||||||
|
return createJdbcValue( value, options );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getExtraCreateTableInfo(
|
public String getExtraCreateTableInfo(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
|
@ -51,21 +79,24 @@ public class OracleBaseStructJdbcType extends StructJdbcType {
|
||||||
.locateUserDefinedType( Identifier.toIdentifier( getSqlTypeName() ) );
|
.locateUserDefinedType( Identifier.toIdentifier( getSqlTypeName() ) );
|
||||||
StringBuilder sb = null;
|
StringBuilder sb = null;
|
||||||
for ( Column column : udt.getColumns() ) {
|
for ( Column column : udt.getColumns() ) {
|
||||||
final JdbcMapping jdbcMapping = (JdbcMapping) column.getValue().getType();
|
final Type columnType = column.getValue().getType();
|
||||||
final String extraCreateTableInfo = jdbcMapping.getJdbcType().getExtraCreateTableInfo(
|
if ( columnType instanceof JdbcMapping ) {
|
||||||
jdbcMapping.getJavaTypeDescriptor(),
|
final JdbcMapping jdbcMapping = (JdbcMapping) columnType;
|
||||||
columnName + "." + column.getName(),
|
final String extraCreateTableInfo = jdbcMapping.getJdbcType().getExtraCreateTableInfo(
|
||||||
tableName,
|
jdbcMapping.getJavaTypeDescriptor(),
|
||||||
database
|
columnName + "." + column.getName(),
|
||||||
);
|
tableName,
|
||||||
if ( !extraCreateTableInfo.isEmpty() ) {
|
database
|
||||||
if ( sb == null ) {
|
);
|
||||||
sb = new StringBuilder();
|
if ( !extraCreateTableInfo.isEmpty() ) {
|
||||||
|
if ( sb == null ) {
|
||||||
|
sb = new StringBuilder();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sb.append( ',' );
|
||||||
|
}
|
||||||
|
sb.append( extraCreateTableInfo );
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
sb.append( ',' );
|
|
||||||
}
|
|
||||||
sb.append( extraCreateTableInfo );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sb != null ? sb.toString() : "";
|
return sb != null ? sb.toString() : "";
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.type.descriptor.ValueBinder;
|
||||||
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descriptor for {@link Types#ARRAY ARRAY} handling.
|
||||||
|
*/
|
||||||
|
public class PostgreSQLArrayJdbcType extends ArrayJdbcType {
|
||||||
|
|
||||||
|
public PostgreSQLArrayJdbcType(JdbcType elementJdbcType) {
|
||||||
|
super( elementJdbcType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) {
|
||||||
|
//noinspection unchecked
|
||||||
|
final ValueBinder<Object> elementBinder = getElementJdbcType().getBinder( ( (BasicPluralJavaType<Object>) javaTypeDescriptor ).getElementJavaType() );
|
||||||
|
return new BasicBinder<>( javaTypeDescriptor, this ) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
|
||||||
|
st.setArray( index, getArray( value, options ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||||
|
throws SQLException {
|
||||||
|
final java.sql.Array arr = getArray( value, options );
|
||||||
|
try {
|
||||||
|
st.setObject( name, arr, java.sql.Types.ARRAY );
|
||||||
|
}
|
||||||
|
catch (SQLException ex) {
|
||||||
|
throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBindValue(X value, WrapperOptions options) throws SQLException {
|
||||||
|
return ( (PostgreSQLArrayJdbcType) getJdbcType() ).getArray( this, elementBinder, value, options );
|
||||||
|
}
|
||||||
|
|
||||||
|
private java.sql.Array getArray(X value, WrapperOptions options) throws SQLException {
|
||||||
|
final PostgreSQLArrayJdbcType arrayJdbcType = (PostgreSQLArrayJdbcType) getJdbcType();
|
||||||
|
final Object[] objects;
|
||||||
|
|
||||||
|
final JdbcType elementJdbcType = arrayJdbcType.getElementJdbcType();
|
||||||
|
if ( elementJdbcType instanceof AggregateJdbcType ) {
|
||||||
|
// The PostgreSQL JDBC driver does not support arrays of structs, which contain byte[]
|
||||||
|
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) elementJdbcType;
|
||||||
|
final Object[] domainObjects = getJavaType().unwrap(
|
||||||
|
value,
|
||||||
|
Object[].class,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
objects = new Object[domainObjects.length];
|
||||||
|
for ( int i = 0; i < domainObjects.length; i++ ) {
|
||||||
|
objects[i] = aggregateJdbcType.createJdbcValue( domainObjects[i], options );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
objects = arrayJdbcType.getArray( this, elementBinder, value, options );
|
||||||
|
}
|
||||||
|
|
||||||
|
final SharedSessionContractImplementor session = options.getSession();
|
||||||
|
final String typeName = arrayJdbcType.getElementTypeName( getJavaType(), session );
|
||||||
|
return session.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection()
|
||||||
|
.createArrayOf( typeName, objects );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PostgreSQLArrayTypeDescriptor(" + getElementJdbcType().toString() + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect;
|
||||||
|
|
||||||
|
import java.sql.Types;
|
||||||
|
|
||||||
|
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory for {@link PostgreSQLArrayJdbcType}.
|
||||||
|
*/
|
||||||
|
public class PostgreSQLArrayJdbcTypeConstructor implements JdbcTypeConstructor {
|
||||||
|
|
||||||
|
public static final PostgreSQLArrayJdbcTypeConstructor INSTANCE = new PostgreSQLArrayJdbcTypeConstructor();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JdbcType resolveType(
|
||||||
|
TypeConfiguration typeConfiguration,
|
||||||
|
Dialect dialect,
|
||||||
|
BasicType<?> elementType,
|
||||||
|
ColumnTypeInformation columnTypeInformation) {
|
||||||
|
return resolveType( typeConfiguration, dialect, elementType.getJdbcType(), columnTypeInformation );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JdbcType resolveType(
|
||||||
|
TypeConfiguration typeConfiguration,
|
||||||
|
Dialect dialect,
|
||||||
|
JdbcType elementType,
|
||||||
|
ColumnTypeInformation columnTypeInformation) {
|
||||||
|
return new PostgreSQLArrayJdbcType( elementType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDefaultSqlTypeCode() {
|
||||||
|
return Types.ARRAY;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1474,6 +1474,8 @@ public class PostgreSQLDialect extends Dialect {
|
||||||
jdbcTypeRegistry.addDescriptor( PostgreSQLEnumJdbcType.INSTANCE );
|
jdbcTypeRegistry.addDescriptor( PostgreSQLEnumJdbcType.INSTANCE );
|
||||||
jdbcTypeRegistry.addDescriptor( PostgreSQLOrdinalEnumJdbcType.INSTANCE );
|
jdbcTypeRegistry.addDescriptor( PostgreSQLOrdinalEnumJdbcType.INSTANCE );
|
||||||
jdbcTypeRegistry.addDescriptor( PostgreSQLUUIDJdbcType.INSTANCE );
|
jdbcTypeRegistry.addDescriptor( PostgreSQLUUIDJdbcType.INSTANCE );
|
||||||
|
|
||||||
|
jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -89,6 +89,11 @@ public class PostgreSQLStructCastingJdbcType extends AbstractPostgreSQLStructJdb
|
||||||
);
|
);
|
||||||
st.setString( name, stringValue );
|
st.setString( name, stringValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBindValue(X value, WrapperOptions options) throws SQLException {
|
||||||
|
return ( (PostgreSQLStructCastingJdbcType) getJdbcType() ).getBindValue( value, options );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,11 @@ public class PostgreSQLStructPGObjectJdbcType extends AbstractPostgreSQLStructJd
|
||||||
holder.setValue( stringValue );
|
holder.setValue( stringValue );
|
||||||
st.setObject( name, holder );
|
st.setObject( name, holder );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBindValue(X value, WrapperOptions options) throws SQLException {
|
||||||
|
return ( (PostgreSQLStructPGObjectJdbcType) getJdbcType() ).getBindValue( value, options );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,18 @@ import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.Internal;
|
import org.hibernate.Internal;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
||||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||||
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.type.SqlTypes;
|
import org.hibernate.type.SqlTypes;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
|
@ -39,12 +45,14 @@ public class StructHelper {
|
||||||
final StructAttributeValues attributeValues = new StructAttributeValues( numberOfAttributeMappings, rawJdbcValues );
|
final StructAttributeValues attributeValues = new StructAttributeValues( numberOfAttributeMappings, rawJdbcValues );
|
||||||
int jdbcIndex = 0;
|
int jdbcIndex = 0;
|
||||||
for ( int i = 0; i < size; i++ ) {
|
for ( int i = 0; i < size; i++ ) {
|
||||||
final ValuedModelPart valuedModelPart = getEmbeddedPart(
|
jdbcIndex += injectAttributeValue(
|
||||||
embeddableMappingType,
|
getEmbeddedPart( embeddableMappingType, i ),
|
||||||
numberOfAttributeMappings,
|
attributeValues,
|
||||||
i
|
i,
|
||||||
|
rawJdbcValues,
|
||||||
|
jdbcIndex,
|
||||||
|
options
|
||||||
);
|
);
|
||||||
jdbcIndex += injectAttributeValue( valuedModelPart, attributeValues, i, rawJdbcValues, jdbcIndex, options );
|
|
||||||
}
|
}
|
||||||
return attributeValues;
|
return attributeValues;
|
||||||
}
|
}
|
||||||
|
@ -104,26 +112,58 @@ public class StructHelper {
|
||||||
else {
|
else {
|
||||||
jdbcValues = values;
|
jdbcValues = values;
|
||||||
}
|
}
|
||||||
int jdbcIndex = 0;
|
injectJdbcValues(
|
||||||
|
embeddableMappingType,
|
||||||
|
values,
|
||||||
|
jdbcValues,
|
||||||
|
0,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
if ( orderMapping != null ) {
|
||||||
|
final Object[] originalJdbcValues = jdbcValues.clone();
|
||||||
|
for ( int i = 0; i < orderMapping.length; i++ ) {
|
||||||
|
jdbcValues[i] = originalJdbcValues[orderMapping[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jdbcValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int injectJdbcValues(
|
||||||
|
EmbeddableMappingType embeddableMappingType,
|
||||||
|
Object domainValue,
|
||||||
|
Object[] jdbcValues,
|
||||||
|
int jdbcIndex,
|
||||||
|
WrapperOptions options) throws SQLException {
|
||||||
|
return injectJdbcValues(
|
||||||
|
embeddableMappingType,
|
||||||
|
embeddableMappingType.getValues( domainValue ),
|
||||||
|
jdbcValues,
|
||||||
|
jdbcIndex,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int injectJdbcValues(
|
||||||
|
EmbeddableMappingType embeddableMappingType,
|
||||||
|
Object[] values,
|
||||||
|
Object[] jdbcValues,
|
||||||
|
int jdbcIndex,
|
||||||
|
WrapperOptions options) throws SQLException {
|
||||||
|
final int jdbcValueCount = embeddableMappingType.getJdbcValueCount();
|
||||||
|
final int valueCount = jdbcValueCount + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
|
||||||
|
int offset = 0;
|
||||||
for ( int i = 0; i < values.length; i++ ) {
|
for ( int i = 0; i < values.length; i++ ) {
|
||||||
final int attributeIndex;
|
offset += injectJdbcValue(
|
||||||
if ( orderMapping == null ) {
|
getEmbeddedPart( embeddableMappingType, i ),
|
||||||
attributeIndex = i;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
attributeIndex = orderMapping[i];
|
|
||||||
}
|
|
||||||
jdbcIndex += injectJdbcValue(
|
|
||||||
getEmbeddedPart( embeddableMappingType, jdbcValueCount, attributeIndex ),
|
|
||||||
values,
|
values,
|
||||||
attributeIndex,
|
i,
|
||||||
jdbcValues,
|
jdbcValues,
|
||||||
jdbcIndex,
|
jdbcIndex + offset,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
assert jdbcIndex == valueCount;
|
assert offset == valueCount;
|
||||||
return jdbcValues;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object instantiate(
|
public static Object instantiate(
|
||||||
|
@ -142,13 +182,10 @@ public class StructHelper {
|
||||||
return instantiator.instantiate( attributeValues, sessionFactory );
|
return instantiator.instantiate( attributeValues, sessionFactory );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ValuedModelPart getEmbeddedPart(
|
public static ValuedModelPart getEmbeddedPart(EmbeddableMappingType embeddableMappingType, int position) {
|
||||||
EmbeddableMappingType embeddableMappingType,
|
return position == embeddableMappingType.getNumberOfAttributeMappings()
|
||||||
int numberOfAttributes,
|
? embeddableMappingType.getDiscriminatorMapping()
|
||||||
int position) {
|
: embeddableMappingType.getAttributeMapping( position );
|
||||||
return position == numberOfAttributes ?
|
|
||||||
embeddableMappingType.getDiscriminatorMapping() :
|
|
||||||
embeddableMappingType.getAttributeMapping( position );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int injectJdbcValue(
|
private static int injectJdbcValue(
|
||||||
|
@ -158,20 +195,65 @@ public class StructHelper {
|
||||||
Object[] jdbcValues,
|
Object[] jdbcValues,
|
||||||
int jdbcIndex,
|
int jdbcIndex,
|
||||||
WrapperOptions options) throws SQLException {
|
WrapperOptions options) throws SQLException {
|
||||||
final MappingType mappedType = attributeMapping.getMappedType();
|
|
||||||
final int jdbcValueCount;
|
final int jdbcValueCount;
|
||||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||||
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
|
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping;
|
||||||
if ( embeddableMappingType.getAggregateMapping() != null ) {
|
if ( toOneAttributeMapping.getSideNature() == ForeignKeyDescriptor.Nature.TARGET ) {
|
||||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableMappingType.getAggregateMapping()
|
return 0;
|
||||||
.getJdbcMapping()
|
}
|
||||||
.getJdbcType();
|
final ForeignKeyDescriptor foreignKeyDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
|
||||||
|
final ValuedModelPart keyPart = foreignKeyDescriptor.getKeyPart();
|
||||||
|
final Object foreignKeyValue = foreignKeyDescriptor.getAssociationKeyFromSide(
|
||||||
|
attributeValues[attributeIndex],
|
||||||
|
ForeignKeyDescriptor.Nature.TARGET,
|
||||||
|
options.getSession()
|
||||||
|
);
|
||||||
|
if ( keyPart instanceof BasicValuedMapping ) {
|
||||||
jdbcValueCount = 1;
|
jdbcValueCount = 1;
|
||||||
jdbcValues[jdbcIndex] = aggregateJdbcType.createJdbcValue(
|
jdbcValues[jdbcIndex] = foreignKeyValue;
|
||||||
attributeValues[attributeIndex],
|
}
|
||||||
|
else if ( keyPart instanceof EmbeddableValuedModelPart ) {
|
||||||
|
final EmbeddableMappingType mappingType = ( (EmbeddableValuedModelPart) keyPart ).getEmbeddableTypeDescriptor();
|
||||||
|
jdbcValueCount = injectJdbcValues(
|
||||||
|
mappingType,
|
||||||
|
foreignKeyValue,
|
||||||
|
jdbcValues,
|
||||||
|
jdbcIndex,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException( "Unsupported foreign key part: " + keyPart );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( attributeMapping instanceof PluralAttributeMapping ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if ( attributeMapping instanceof DiscriminatedAssociationAttributeMapping ) {
|
||||||
|
jdbcValueCount = attributeMapping.decompose(
|
||||||
|
attributeValues[attributeIndex],
|
||||||
|
jdbcIndex,
|
||||||
|
jdbcValues,
|
||||||
|
options,
|
||||||
|
(valueIndex, objects, wrapperOptions, value, jdbcValueMapping) -> {
|
||||||
|
objects[valueIndex] = value;
|
||||||
|
},
|
||||||
|
options.getSession()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if ( attributeMapping instanceof EmbeddableValuedModelPart ) {
|
||||||
|
final EmbeddableValuedModelPart embeddableValuedModelPart = (EmbeddableValuedModelPart) attributeMapping;
|
||||||
|
final EmbeddableMappingType embeddableMappingType = embeddableValuedModelPart.getMappedType();
|
||||||
|
if ( embeddableMappingType.getAggregateMapping() != null ) {
|
||||||
|
jdbcValueCount = 1;
|
||||||
|
jdbcValues[jdbcIndex] = embeddableMappingType.getAggregateMapping()
|
||||||
|
.getJdbcMapping()
|
||||||
|
.getJdbcValueBinder()
|
||||||
|
.getBindValue(
|
||||||
|
attributeValues[attributeIndex],
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
jdbcValueCount = embeddableMappingType.getJdbcValueCount() + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
|
jdbcValueCount = embeddableMappingType.getJdbcValueCount() + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
|
||||||
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
|
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
|
||||||
|
@ -180,7 +262,7 @@ public class StructHelper {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for ( int i = 0; i < numberOfValues; i++ ) {
|
for ( int i = 0; i < numberOfValues; i++ ) {
|
||||||
offset += injectJdbcValue(
|
offset += injectJdbcValue(
|
||||||
getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, i ),
|
getEmbeddedPart( embeddableMappingType, i ),
|
||||||
subValues,
|
subValues,
|
||||||
i,
|
i,
|
||||||
jdbcValues,
|
jdbcValues,
|
||||||
|
@ -251,23 +333,27 @@ public class StructHelper {
|
||||||
int[] inverseMapping,
|
int[] inverseMapping,
|
||||||
Object[] sourceJdbcValues,
|
Object[] sourceJdbcValues,
|
||||||
Object[] targetJdbcValues) {
|
Object[] targetJdbcValues) {
|
||||||
final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
|
for ( int i = 0; i < inverseMapping.length; i++ ) {
|
||||||
int targetJdbcOffset = 0;
|
targetJdbcValues[i] = sourceJdbcValues[inverseMapping[i]];
|
||||||
for ( int i = 0; i < numberOfAttributes + ( embeddableMappingType.isPolymorphic() ? 1 : 0 ); i++ ) {
|
|
||||||
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributes, i );
|
|
||||||
final MappingType mappedType = attributeMapping.getMappedType();
|
|
||||||
final int jdbcValueCount = getJdbcValueCount( mappedType );
|
|
||||||
|
|
||||||
final int attributeIndex = inverseMapping[i];
|
|
||||||
int sourceJdbcIndex = 0;
|
|
||||||
for ( int j = 0; j < attributeIndex; j++ ) {
|
|
||||||
sourceJdbcIndex += getJdbcValueCount( embeddableMappingType.getAttributeMapping( j ).getMappedType() );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( int j = 0; j < jdbcValueCount; j++ ) {
|
|
||||||
targetJdbcValues[targetJdbcOffset++] = sourceJdbcValues[sourceJdbcIndex + j];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
|
||||||
|
// int targetJdbcOffset = 0;
|
||||||
|
// for ( int i = 0; i < numberOfAttributes + ( embeddableMappingType.isPolymorphic() ? 1 : 0 ); i++ ) {
|
||||||
|
// final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, i );
|
||||||
|
// final MappingType mappedType = attributeMapping.getMappedType();
|
||||||
|
// final int jdbcValueCount = getJdbcValueCount( mappedType );
|
||||||
|
//
|
||||||
|
// final int attributeIndex = inverseMapping[i];
|
||||||
|
// int sourceJdbcIndex = 0;
|
||||||
|
// for ( int j = 0; j < attributeIndex; j++ ) {
|
||||||
|
// sourceJdbcIndex += getJdbcValueCount( embeddableMappingType.getAttributeMapping( j ).getMappedType() );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for ( int j = 0; j < jdbcValueCount; j++ ) {
|
||||||
|
// targetJdbcValues[targetJdbcOffset++] = sourceJdbcValues[sourceJdbcIndex + j];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getJdbcValueCount(MappingType mappedType) {
|
public static int getJdbcValueCount(MappingType mappedType) {
|
||||||
|
|
|
@ -13,10 +13,16 @@ import java.sql.SQLException;
|
||||||
import java.sql.Struct;
|
import java.sql.Struct;
|
||||||
|
|
||||||
import org.hibernate.boot.model.naming.Identifier;
|
import org.hibernate.boot.model.naming.Identifier;
|
||||||
|
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||||
import org.hibernate.type.BasicPluralType;
|
import org.hibernate.type.BasicPluralType;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
|
@ -144,9 +150,12 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException {
|
public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException {
|
||||||
final Object[] attributes = ( (Struct) rawJdbcValue ).getAttributes();
|
final Object[] jdbcValues = ( (Struct) rawJdbcValue ).getAttributes();
|
||||||
wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, attributes, 0, options );
|
if ( orderMapping != null ) {
|
||||||
return attributes;
|
StructHelper.orderJdbcValues( embeddableMappingType, inverseOrderMapping, jdbcValues.clone(), jdbcValues );
|
||||||
|
}
|
||||||
|
wrapRawJdbcValues( embeddableMappingType, jdbcValues, 0, options );
|
||||||
|
return jdbcValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -198,18 +207,21 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final Struct struct = (Struct) object;
|
final Struct struct = (Struct) object;
|
||||||
final Object[] values = struct.getAttributes();
|
final Object[] jdbcValues = struct.getAttributes();
|
||||||
final boolean jdbcRepresentation = getJavaType().getJavaTypeClass() == Object[].class;
|
final boolean jdbcRepresentation = getJavaType().getJavaTypeClass() == Object[].class;
|
||||||
if ( jdbcRepresentation ) {
|
if ( jdbcRepresentation ) {
|
||||||
wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, values, 0, options );
|
if ( orderMapping != null ) {
|
||||||
|
StructHelper.orderJdbcValues( embeddableMappingType, inverseOrderMapping, jdbcValues.clone(), jdbcValues );
|
||||||
|
}
|
||||||
|
wrapRawJdbcValues( embeddableMappingType, jdbcValues, 0, options );
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return (X) values;
|
return (X) jdbcValues;
|
||||||
}
|
}
|
||||||
assert embeddableMappingType != null && embeddableMappingType.getJavaType() == getJavaType();
|
assert embeddableMappingType != null && embeddableMappingType.getJavaType() == getJavaType();
|
||||||
final StructAttributeValues attributeValues = getAttributeValues(
|
final StructAttributeValues attributeValues = getAttributeValues(
|
||||||
embeddableMappingType,
|
embeddableMappingType,
|
||||||
orderMapping,
|
orderMapping,
|
||||||
values,
|
jdbcValues,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
|
@ -240,9 +252,8 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
||||||
else {
|
else {
|
||||||
attributeIndex = orderMapping[i];
|
attributeIndex = orderMapping[i];
|
||||||
}
|
}
|
||||||
final ValuedModelPart modelPart = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, attributeIndex );
|
|
||||||
jdbcIndex += injectAttributeValue(
|
jdbcIndex += injectAttributeValue(
|
||||||
modelPart,
|
getEmbeddedPart( embeddableMappingType, attributeIndex ),
|
||||||
attributeValues,
|
attributeValues,
|
||||||
attributeIndex,
|
attributeIndex,
|
||||||
rawJdbcValues,
|
rawJdbcValues,
|
||||||
|
@ -381,117 +392,150 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
||||||
|
|
||||||
private int wrapRawJdbcValues(
|
private int wrapRawJdbcValues(
|
||||||
EmbeddableMappingType embeddableMappingType,
|
EmbeddableMappingType embeddableMappingType,
|
||||||
int[] orderMapping,
|
|
||||||
int[] inverseOrderMapping,
|
|
||||||
Object[] jdbcValues,
|
Object[] jdbcValues,
|
||||||
int jdbcIndex,
|
int jdbcIndex,
|
||||||
WrapperOptions options) throws SQLException {
|
WrapperOptions options) throws SQLException {
|
||||||
final Object[] targetJdbcValues;
|
|
||||||
if ( orderMapping == null ) {
|
|
||||||
targetJdbcValues = jdbcValues;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
targetJdbcValues = jdbcValues.clone();
|
|
||||||
}
|
|
||||||
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
|
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
|
||||||
for ( int i = 0; i < numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 ); i++ ) {
|
for ( int i = 0; i < numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 ); i++ ) {
|
||||||
final ValuedModelPart attributeMapping;
|
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, i );
|
||||||
if ( orderMapping == null ) {
|
if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||||
attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, i );
|
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping;
|
||||||
|
if ( toOneAttributeMapping.getSideNature() == ForeignKeyDescriptor.Nature.TARGET ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final ForeignKeyDescriptor foreignKeyDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
|
||||||
|
final ValuedModelPart keyPart = foreignKeyDescriptor.getKeyPart();
|
||||||
|
if ( keyPart instanceof BasicValuedMapping ) {
|
||||||
|
wrapRawJdbcValue( keyPart.getSingleJdbcMapping(), jdbcValues, jdbcIndex, options );
|
||||||
|
jdbcIndex++;
|
||||||
|
}
|
||||||
|
else if ( keyPart instanceof EmbeddableValuedModelPart ) {
|
||||||
|
final EmbeddableMappingType mappingType = ( (EmbeddableValuedModelPart) keyPart ).getEmbeddableTypeDescriptor();
|
||||||
|
jdbcIndex = wrapRawJdbcValues(
|
||||||
|
mappingType,
|
||||||
|
jdbcValues,
|
||||||
|
jdbcIndex,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException( "Unsupported foreign key part: " + keyPart );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if ( attributeMapping instanceof PluralAttributeMapping ) {
|
||||||
attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, orderMapping[i] );
|
continue;
|
||||||
}
|
}
|
||||||
final MappingType mappedType = attributeMapping.getMappedType();
|
else if ( attributeMapping instanceof DiscriminatedAssociationAttributeMapping ) {
|
||||||
|
final DiscriminatedAssociationAttributeMapping discriminatedAssociationAttributeMapping = (DiscriminatedAssociationAttributeMapping) attributeMapping;
|
||||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
wrapRawJdbcValue(
|
||||||
final EmbeddableMappingType embeddableType = (EmbeddableMappingType) mappedType;
|
discriminatedAssociationAttributeMapping.getDiscriminatorPart().getSingleJdbcMapping(),
|
||||||
|
jdbcValues,
|
||||||
|
jdbcIndex,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
jdbcIndex++;
|
||||||
|
wrapRawJdbcValue(
|
||||||
|
discriminatedAssociationAttributeMapping.getKeyPart().getSingleJdbcMapping(),
|
||||||
|
jdbcValues,
|
||||||
|
jdbcIndex,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
jdbcIndex++;
|
||||||
|
}
|
||||||
|
else if ( attributeMapping instanceof EmbeddableValuedModelPart ) {
|
||||||
|
final EmbeddableValuedModelPart embeddableValuedModelPart = (EmbeddableValuedModelPart) attributeMapping;
|
||||||
|
final EmbeddableMappingType embeddableType = embeddableValuedModelPart.getMappedType();
|
||||||
if ( embeddableType.getAggregateMapping() != null ) {
|
if ( embeddableType.getAggregateMapping() != null ) {
|
||||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableType.getAggregateMapping()
|
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableType.getAggregateMapping()
|
||||||
.getJdbcMapping()
|
.getJdbcMapping()
|
||||||
.getJdbcType();
|
.getJdbcType();
|
||||||
final Object rawJdbcValue = targetJdbcValues[jdbcIndex];
|
final Object rawJdbcValue = jdbcValues[jdbcIndex];
|
||||||
targetJdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
|
jdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
|
||||||
jdbcIndex++;
|
jdbcIndex++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
jdbcIndex = wrapRawJdbcValues( embeddableType, null, null, targetJdbcValues, jdbcIndex, options );
|
jdbcIndex = wrapRawJdbcValues( embeddableType, jdbcValues, jdbcIndex, options );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert attributeMapping.getJdbcTypeCount() == 1;
|
assert attributeMapping.getJdbcTypeCount() == 1;
|
||||||
final Object rawJdbcValue = targetJdbcValues[jdbcIndex];
|
wrapRawJdbcValue( attributeMapping.getSingleJdbcMapping(), jdbcValues, jdbcIndex, options );
|
||||||
if ( rawJdbcValue != null ) {
|
|
||||||
final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping();
|
|
||||||
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
|
|
||||||
case SqlTypes.TIME_WITH_TIMEZONE:
|
|
||||||
case SqlTypes.TIME_UTC:
|
|
||||||
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
|
|
||||||
case SqlTypes.TIMESTAMP_UTC:
|
|
||||||
// Only transform the raw jdbc value if it could be a TIMESTAMPTZ
|
|
||||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType()
|
|
||||||
.wrap( transformRawJdbcValue( rawJdbcValue, options ), options );
|
|
||||||
break;
|
|
||||||
case SqlTypes.ARRAY:
|
|
||||||
final BasicType<?> elementType = ( (BasicPluralType<?, ?>) jdbcMapping ).getElementType();
|
|
||||||
final JdbcType elementJdbcType = elementType.getJdbcType();
|
|
||||||
final Object[] array;
|
|
||||||
final Object[] newArray;
|
|
||||||
switch ( elementJdbcType.getDefaultSqlTypeCode() ) {
|
|
||||||
case SqlTypes.TIME_WITH_TIMEZONE:
|
|
||||||
case SqlTypes.TIME_UTC:
|
|
||||||
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
|
|
||||||
case SqlTypes.TIMESTAMP_UTC:
|
|
||||||
// Only transform the raw jdbc value if it could be a TIMESTAMPTZ
|
|
||||||
array = (Object[]) ((java.sql.Array) rawJdbcValue).getArray();
|
|
||||||
newArray = new Object[array.length];
|
|
||||||
for ( int j = 0; j < array.length; j++ ) {
|
|
||||||
newArray[j] = elementType.getJdbcJavaType().wrap(
|
|
||||||
transformRawJdbcValue( array[j], options ),
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( newArray, options );
|
|
||||||
break;
|
|
||||||
case SqlTypes.STRUCT:
|
|
||||||
case SqlTypes.JSON:
|
|
||||||
case SqlTypes.SQLXML:
|
|
||||||
array = (Object[]) ( (java.sql.Array) rawJdbcValue ).getArray();
|
|
||||||
newArray = new Object[array.length];
|
|
||||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) elementJdbcType;
|
|
||||||
final EmbeddableMappingType subEmbeddableMappingType = aggregateJdbcType.getEmbeddableMappingType();
|
|
||||||
for ( int j = 0; j < array.length; j++ ) {
|
|
||||||
final StructAttributeValues subValues = StructHelper.getAttributeValues(
|
|
||||||
subEmbeddableMappingType,
|
|
||||||
aggregateJdbcType.extractJdbcValues(
|
|
||||||
array[j],
|
|
||||||
options
|
|
||||||
),
|
|
||||||
options
|
|
||||||
);
|
|
||||||
newArray[j] = instantiate( subEmbeddableMappingType, subValues, options.getSessionFactory() );
|
|
||||||
}
|
|
||||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( newArray, options );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jdbcIndex++;
|
jdbcIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( orderMapping != null ) {
|
|
||||||
StructHelper.orderJdbcValues( embeddableMappingType, inverseOrderMapping, targetJdbcValues, jdbcValues );
|
|
||||||
}
|
|
||||||
return jdbcIndex;
|
return jdbcIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void wrapRawJdbcValue(
|
||||||
|
JdbcMapping jdbcMapping,
|
||||||
|
Object[] jdbcValues,
|
||||||
|
int jdbcIndex,
|
||||||
|
WrapperOptions options) throws SQLException {
|
||||||
|
final Object rawJdbcValue = jdbcValues[jdbcIndex];
|
||||||
|
if ( rawJdbcValue == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
|
||||||
|
case SqlTypes.TIME_WITH_TIMEZONE:
|
||||||
|
case SqlTypes.TIME_UTC:
|
||||||
|
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
|
||||||
|
case SqlTypes.TIMESTAMP_UTC:
|
||||||
|
// Only transform the raw jdbc value if it could be a TIMESTAMPTZ
|
||||||
|
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType()
|
||||||
|
.wrap( transformRawJdbcValue( rawJdbcValue, options ), options );
|
||||||
|
break;
|
||||||
|
case SqlTypes.ARRAY:
|
||||||
|
final BasicType<?> elementType = ( (BasicPluralType<?, ?>) jdbcMapping ).getElementType();
|
||||||
|
final JdbcType elementJdbcType = elementType.getJdbcType();
|
||||||
|
final Object[] array;
|
||||||
|
final Object[] newArray;
|
||||||
|
switch ( elementJdbcType.getDefaultSqlTypeCode() ) {
|
||||||
|
case SqlTypes.TIME_WITH_TIMEZONE:
|
||||||
|
case SqlTypes.TIME_UTC:
|
||||||
|
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
|
||||||
|
case SqlTypes.TIMESTAMP_UTC:
|
||||||
|
// Only transform the raw jdbc value if it could be a TIMESTAMPTZ
|
||||||
|
array = (Object[]) ((java.sql.Array) rawJdbcValue ).getArray();
|
||||||
|
newArray = new Object[array.length];
|
||||||
|
for ( int j = 0; j < array.length; j++ ) {
|
||||||
|
newArray[j] = elementType.getJdbcJavaType().wrap(
|
||||||
|
transformRawJdbcValue( array[j], options ),
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
|
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( newArray, options );
|
||||||
|
break;
|
||||||
|
case SqlTypes.STRUCT:
|
||||||
|
case SqlTypes.JSON:
|
||||||
|
case SqlTypes.SQLXML:
|
||||||
|
array = (Object[]) ( (java.sql.Array) rawJdbcValue ).getArray();
|
||||||
|
newArray = new Object[array.length];
|
||||||
|
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) elementJdbcType;
|
||||||
|
final EmbeddableMappingType subEmbeddableMappingType = aggregateJdbcType.getEmbeddableMappingType();
|
||||||
|
for ( int j = 0; j < array.length; j++ ) {
|
||||||
|
final StructAttributeValues subValues = StructHelper.getAttributeValues(
|
||||||
|
subEmbeddableMappingType,
|
||||||
|
aggregateJdbcType.extractJdbcValues(
|
||||||
|
array[j],
|
||||||
|
options
|
||||||
|
),
|
||||||
|
options
|
||||||
|
);
|
||||||
|
newArray[j] = instantiate( subEmbeddableMappingType, subValues, options.getSessionFactory() );
|
||||||
|
}
|
||||||
|
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( newArray, options );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) {
|
protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) {
|
||||||
return rawJdbcValue;
|
return rawJdbcValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -493,7 +493,7 @@ public class XmlHelper {
|
||||||
if ( array[i] == null ) {
|
if ( array[i] == null ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributes, i );
|
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, i );
|
||||||
if ( attributeMapping instanceof SelectableMapping ) {
|
if ( attributeMapping instanceof SelectableMapping ) {
|
||||||
final SelectableMapping selectable = (SelectableMapping) attributeMapping;
|
final SelectableMapping selectable = (SelectableMapping) attributeMapping;
|
||||||
final String tagName = selectable.getSelectableName();
|
final String tagName = selectable.getSelectableName();
|
||||||
|
|
|
@ -94,7 +94,10 @@ public class GeneratedValueBasicResultBuilder implements ResultBuilder {
|
||||||
return new BasicResult<>(
|
return new BasicResult<>(
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
null,
|
null,
|
||||||
modelPart.getJdbcMapping()
|
modelPart.getJdbcMapping(),
|
||||||
|
navigablePath,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.hibernate.sql.Template;
|
||||||
import static org.hibernate.type.SqlTypes.JSON_ARRAY;
|
import static org.hibernate.type.SqlTypes.JSON_ARRAY;
|
||||||
import static org.hibernate.type.SqlTypes.STRUCT_ARRAY;
|
import static org.hibernate.type.SqlTypes.STRUCT_ARRAY;
|
||||||
import static org.hibernate.type.SqlTypes.STRUCT_TABLE;
|
import static org.hibernate.type.SqlTypes.STRUCT_TABLE;
|
||||||
|
import static org.hibernate.type.SqlTypes.XML_ARRAY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An aggregate column is a column of type {@link org.hibernate.type.SqlTypes#STRUCT},
|
* An aggregate column is a column of type {@link org.hibernate.type.SqlTypes#STRUCT},
|
||||||
|
@ -79,7 +80,9 @@ public class AggregateColumn extends Column {
|
||||||
final AggregateColumn parentAggregateColumn = component.getParentAggregateColumn();
|
final AggregateColumn parentAggregateColumn = component.getParentAggregateColumn();
|
||||||
final String simpleAggregateName = aggregateColumn.getQuotedName( dialect );
|
final String simpleAggregateName = aggregateColumn.getQuotedName( dialect );
|
||||||
final String aggregateSelectableExpression;
|
final String aggregateSelectableExpression;
|
||||||
if ( parentAggregateColumn == null ) {
|
// If the aggregate column is an array, drop the parent read expression, because this is a NestedColumnReference
|
||||||
|
// and will require special rendering
|
||||||
|
if ( parentAggregateColumn == null || isArray( aggregateColumn ) ) {
|
||||||
aggregateSelectableExpression = getRootAggregateSelectableExpression( aggregateColumn, simpleAggregateName );
|
aggregateSelectableExpression = getRootAggregateSelectableExpression( aggregateColumn, simpleAggregateName );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -99,13 +102,23 @@ public class AggregateColumn extends Column {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getRootAggregateSelectableExpression(AggregateColumn aggregateColumn, String simpleAggregateName) {
|
private static String getRootAggregateSelectableExpression(AggregateColumn aggregateColumn, String simpleAggregateName) {
|
||||||
|
if ( isArray( aggregateColumn ) ) {
|
||||||
|
return Template.TEMPLATE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Template.TEMPLATE + "." + simpleAggregateName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isArray(AggregateColumn aggregateColumn) {
|
||||||
switch ( aggregateColumn.getTypeCode() ) {
|
switch ( aggregateColumn.getTypeCode() ) {
|
||||||
case JSON_ARRAY:
|
case JSON_ARRAY:
|
||||||
|
case XML_ARRAY:
|
||||||
case STRUCT_ARRAY:
|
case STRUCT_ARRAY:
|
||||||
case STRUCT_TABLE:
|
case STRUCT_TABLE:
|
||||||
return Template.TEMPLATE;
|
return true;
|
||||||
default:
|
default:
|
||||||
return Template.TEMPLATE + "." + simpleAggregateName;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -967,7 +967,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
||||||
return aggregateColumn == null
|
return aggregateColumn == null
|
||||||
? jdbcTypeCode
|
? jdbcTypeCode
|
||||||
: getDialect().getAggregateSupport()
|
: getDialect().getAggregateSupport()
|
||||||
.aggregateComponentSqlTypeCode( aggregateColumn.getSqlTypeCode(), jdbcTypeCode );
|
.aggregateComponentSqlTypeCode( aggregateColumn.getSqlTypeCode( getMetadata() ), jdbcTypeCode );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.Remove;
|
||||||
import org.hibernate.annotations.common.reflection.XClass;
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
import org.hibernate.boot.model.relational.Database;
|
import org.hibernate.boot.model.relational.Database;
|
||||||
import org.hibernate.boot.model.relational.ExportableProducer;
|
import org.hibernate.boot.model.relational.ExportableProducer;
|
||||||
|
import org.hibernate.boot.model.relational.QualifiedName;
|
||||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||||
import org.hibernate.boot.model.source.internal.hbm.MappingDocument;
|
import org.hibernate.boot.model.source.internal.hbm.MappingDocument;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
|
@ -93,7 +94,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
||||||
|
|
||||||
private AggregateColumn aggregateColumn;
|
private AggregateColumn aggregateColumn;
|
||||||
private AggregateColumn parentAggregateColumn;
|
private AggregateColumn parentAggregateColumn;
|
||||||
private String structName;
|
private QualifiedName structName;
|
||||||
private String[] structColumnNames;
|
private String[] structColumnNames;
|
||||||
private transient Class<?> componentClass;
|
private transient Class<?> componentClass;
|
||||||
// lazily computed based on 'properties' field: invalidate by setting to null when properties are modified
|
// lazily computed based on 'properties' field: invalidate by setting to null when properties are modified
|
||||||
|
@ -307,11 +308,11 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
||||||
this.parentAggregateColumn = parentAggregateColumn;
|
this.parentAggregateColumn = parentAggregateColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStructName() {
|
public QualifiedName getStructName() {
|
||||||
return structName;
|
return structName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStructName(String structName) {
|
public void setStructName(QualifiedName structName) {
|
||||||
this.structName = structName;
|
this.structName = structName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,8 @@ public interface CollectionPart extends ValuedModelPart, Fetchable, JavaTypedExp
|
||||||
|
|
||||||
Nature getNature();
|
Nature getNature();
|
||||||
|
|
||||||
|
PluralAttributeMapping getCollectionAttribute();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default String getPartName() {
|
default String getPartName() {
|
||||||
return getNature().getName();
|
return getNature().getName();
|
||||||
|
|
|
@ -12,9 +12,11 @@ import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import org.hibernate.internal.util.IndexedConsumer;
|
import org.hibernate.internal.util.IndexedConsumer;
|
||||||
import org.hibernate.internal.util.MutableInteger;
|
import org.hibernate.internal.util.MutableInteger;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
||||||
import org.hibernate.property.access.spi.Getter;
|
import org.hibernate.property.access.spi.Getter;
|
||||||
import org.hibernate.spi.NavigablePath;
|
import org.hibernate.spi.NavigablePath;
|
||||||
|
@ -156,9 +158,43 @@ public interface EmbeddableMappingType extends ManagedMappingType, SelectableMap
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for ( int i = 0; i < numberOfAttributeMappings; i++ ) {
|
for ( int i = 0; i < numberOfAttributeMappings; i++ ) {
|
||||||
final AttributeMapping attributeMapping = getAttributeMapping( i );
|
final AttributeMapping attributeMapping = getAttributeMapping( i );
|
||||||
final MappingType mappedType = attributeMapping.getMappedType();
|
if ( attributeMapping instanceof DiscriminatedAssociationAttributeMapping ) {
|
||||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
final DiscriminatedAssociationAttributeMapping discriminatedAssociationAttributeMapping = (DiscriminatedAssociationAttributeMapping) attributeMapping;
|
||||||
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
|
if ( count == columnIndex ) {
|
||||||
|
return discriminatedAssociationAttributeMapping.getDiscriminatorMapping();
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
if ( count == columnIndex ) {
|
||||||
|
return discriminatedAssociationAttributeMapping.getKeyPart();
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
else if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||||
|
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping;
|
||||||
|
if ( toOneAttributeMapping.getSideNature() == ForeignKeyDescriptor.Nature.KEY ) {
|
||||||
|
final ValuedModelPart keyPart = toOneAttributeMapping.getForeignKeyDescriptor().getKeyPart();
|
||||||
|
if ( keyPart instanceof BasicValuedMapping ) {
|
||||||
|
if ( count == columnIndex ) {
|
||||||
|
return (SelectableMapping) keyPart;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
else if ( keyPart instanceof EmbeddableValuedModelPart ) {
|
||||||
|
final EmbeddableMappingType mappingType = ( (EmbeddableValuedModelPart) keyPart ).getEmbeddableTypeDescriptor();
|
||||||
|
final SelectableMapping selectable = mappingType.getJdbcValueSelectable( columnIndex - count );
|
||||||
|
if ( selectable != null ) {
|
||||||
|
return selectable;
|
||||||
|
}
|
||||||
|
count += mappingType.getJdbcValueCount();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException( "Unsupported foreign key part: " + keyPart );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( attributeMapping instanceof EmbeddableValuedModelPart ) {
|
||||||
|
final EmbeddableValuedModelPart embeddableValuedModelPart = (EmbeddableValuedModelPart) attributeMapping;
|
||||||
|
final EmbeddableMappingType embeddableMappingType = embeddableValuedModelPart.getMappedType();
|
||||||
final SelectableMapping aggregateMapping = embeddableMappingType.getAggregateMapping();
|
final SelectableMapping aggregateMapping = embeddableMappingType.getAggregateMapping();
|
||||||
if ( aggregateMapping == null ) {
|
if ( aggregateMapping == null ) {
|
||||||
final SelectableMapping subSelectable = embeddableMappingType.getJdbcValueSelectable( columnIndex - count );
|
final SelectableMapping subSelectable = embeddableMappingType.getJdbcValueSelectable( columnIndex - count );
|
||||||
|
@ -176,7 +212,10 @@ public interface EmbeddableMappingType extends ManagedMappingType, SelectableMap
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( count == columnIndex ) {
|
if ( count == columnIndex ) {
|
||||||
return (SelectableMapping) attributeMapping;
|
if ( attributeMapping instanceof SelectableMapping ) {
|
||||||
|
return (SelectableMapping) attributeMapping;
|
||||||
|
}
|
||||||
|
assert attributeMapping.getJdbcTypeCount() == 0;
|
||||||
}
|
}
|
||||||
count += attributeMapping.getJdbcTypeCount();
|
count += attributeMapping.getJdbcTypeCount();
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ public interface PluralAttributeMapping
|
||||||
TableGroup parentTableGroup,
|
TableGroup parentTableGroup,
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
return new BasicResult( 0, null, getJavaType() );
|
return new BasicResult( 0, null, getJavaType(), null, null, false, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
String getSeparateCollectionTable();
|
String getSeparateCollectionTable();
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.IndexedConsumer;
|
import org.hibernate.internal.util.IndexedConsumer;
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorConverter;
|
import org.hibernate.metamodel.mapping.DiscriminatorConverter;
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorType;
|
import org.hibernate.metamodel.mapping.DiscriminatorType;
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorValueDetails;
|
|
||||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
|
@ -124,7 +123,9 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
|
||||||
resultVariable,
|
resultVariable,
|
||||||
discriminatorType.getJavaTypeDescriptor(),
|
discriminatorType.getJavaTypeDescriptor(),
|
||||||
discriminatorType.getValueConverter(),
|
discriminatorType.getValueConverter(),
|
||||||
navigablePath
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +176,10 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
|
||||||
this,
|
this,
|
||||||
discriminatorType.getValueConverter(),
|
discriminatorType.getValueConverter(),
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
true,
|
||||||
|
creationState,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,11 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
|
||||||
return nature;
|
return nature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PluralAttributeMapping getCollectionAttribute() {
|
||||||
|
return collectionDescriptor.getAttributeMapping();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFetchableName() {
|
public String getFetchableName() {
|
||||||
return nature.getName();
|
return nature.getName();
|
||||||
|
|
|
@ -37,7 +37,6 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
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.Fetch;
|
|
||||||
import org.hibernate.sql.results.graph.FetchOptions;
|
import org.hibernate.sql.results.graph.FetchOptions;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
import org.hibernate.sql.results.graph.FetchParent;
|
||||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||||
|
@ -59,6 +58,8 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
||||||
|
|
||||||
private final String table;
|
private final String table;
|
||||||
private final String column;
|
private final String column;
|
||||||
|
private final String customReadExpression;
|
||||||
|
private final String customWriteExpression;
|
||||||
private final String columnDefinition;
|
private final String columnDefinition;
|
||||||
private final Long length;
|
private final Long length;
|
||||||
private final Integer precision;
|
private final Integer precision;
|
||||||
|
@ -75,7 +76,7 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
||||||
NavigableRole partRole,
|
NavigableRole partRole,
|
||||||
DiscriminatedAssociationModelPart declaringType,
|
DiscriminatedAssociationModelPart declaringType,
|
||||||
String table,
|
String table,
|
||||||
String column,
|
String column, String customReadExpression, String customWriteExpression,
|
||||||
String columnDefinition,
|
String columnDefinition,
|
||||||
Long length,
|
Long length,
|
||||||
Integer precision,
|
Integer precision,
|
||||||
|
@ -90,6 +91,8 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
||||||
this.declaringType = declaringType;
|
this.declaringType = declaringType;
|
||||||
this.table = table;
|
this.table = table;
|
||||||
this.column = column;
|
this.column = column;
|
||||||
|
this.customReadExpression = customReadExpression;
|
||||||
|
this.customWriteExpression = customWriteExpression;
|
||||||
this.columnDefinition = columnDefinition;
|
this.columnDefinition = columnDefinition;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.precision = precision;
|
this.precision = precision;
|
||||||
|
@ -160,12 +163,12 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCustomReadExpression() {
|
public String getCustomReadExpression() {
|
||||||
return null;
|
return customReadExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCustomWriteExpression() {
|
public String getCustomWriteExpression() {
|
||||||
return null;
|
return customWriteExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -326,7 +329,8 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
creationState,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +355,9 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
jdbcMapping(),
|
jdbcMapping(),
|
||||||
navigablePath
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
||||||
private final String table;
|
private final String table;
|
||||||
private final String column;
|
private final String column;
|
||||||
private final DiscriminatedAssociationModelPart anyPart;
|
private final DiscriminatedAssociationModelPart anyPart;
|
||||||
|
private final String customReadExpression;
|
||||||
|
private final String customWriteExpression;
|
||||||
private final String columnDefinition;
|
private final String columnDefinition;
|
||||||
private final Long length;
|
private final Long length;
|
||||||
private final Integer precision;
|
private final Integer precision;
|
||||||
|
@ -63,6 +65,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
||||||
DiscriminatedAssociationModelPart anyPart,
|
DiscriminatedAssociationModelPart anyPart,
|
||||||
String table,
|
String table,
|
||||||
String column,
|
String column,
|
||||||
|
String customReadExpression,
|
||||||
|
String customWriteExpression,
|
||||||
String columnDefinition,
|
String columnDefinition,
|
||||||
Long length,
|
Long length,
|
||||||
Integer precision,
|
Integer precision,
|
||||||
|
@ -76,6 +80,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
||||||
this.table = table;
|
this.table = table;
|
||||||
this.column = column;
|
this.column = column;
|
||||||
this.anyPart = anyPart;
|
this.anyPart = anyPart;
|
||||||
|
this.customReadExpression = customReadExpression;
|
||||||
|
this.customWriteExpression = customWriteExpression;
|
||||||
this.columnDefinition = columnDefinition;
|
this.columnDefinition = columnDefinition;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.precision = precision;
|
this.precision = precision;
|
||||||
|
@ -124,12 +130,12 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCustomReadExpression() {
|
public String getCustomReadExpression() {
|
||||||
return null;
|
return customReadExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCustomWriteExpression() {
|
public String getCustomWriteExpression() {
|
||||||
return null;
|
return customWriteExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -242,7 +248,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
creationState,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +340,9 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
navigablePath
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -337,7 +337,9 @@ public class BasicAttributeMapping
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
navigablePath
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,10 +393,12 @@ public class BasicAttributeMapping
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
final int valuesArrayPosition;
|
final int valuesArrayPosition;
|
||||||
boolean coerceResultType = false;
|
boolean coerceResultType = false;
|
||||||
|
final SqlSelection sqlSelection;
|
||||||
if ( fetchTiming == FetchTiming.DELAYED && isLazy ) {
|
if ( fetchTiming == FetchTiming.DELAYED && isLazy ) {
|
||||||
// Lazy property. A valuesArrayPosition of -1 will lead to
|
// Lazy property. A valuesArrayPosition of -1 will lead to
|
||||||
// returning a domain result assembler that returns LazyPropertyInitializer.UNFETCHED_PROPERTY
|
// returning a domain result assembler that returns LazyPropertyInitializer.UNFETCHED_PROPERTY
|
||||||
valuesArrayPosition = -1;
|
valuesArrayPosition = -1;
|
||||||
|
sqlSelection = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||||
|
@ -404,7 +408,7 @@ public class BasicAttributeMapping
|
||||||
|
|
||||||
assert tableGroup != null;
|
assert tableGroup != null;
|
||||||
|
|
||||||
final SqlSelection sqlSelection = resolveSqlSelection(
|
sqlSelection = resolveSqlSelection(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
tableGroup,
|
tableGroup,
|
||||||
fetchParent,
|
fetchParent,
|
||||||
|
@ -422,9 +426,12 @@ public class BasicAttributeMapping
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
|
getJdbcMapping().getValueConverter(),
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
|
true,
|
||||||
creationState,
|
creationState,
|
||||||
coerceResultType
|
coerceResultType,
|
||||||
|
sqlSelection != null && !sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,7 +231,9 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
entityPersister.getIdentifierMapping().getSingleJdbcMapping(),
|
entityPersister.getIdentifierMapping().getSingleJdbcMapping(),
|
||||||
navigablePath
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,10 +427,13 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
|
getJdbcMapping().getValueConverter(),
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
|
true,
|
||||||
creationState,
|
creationState,
|
||||||
// if the expression type is different that the expected type coerce the value
|
// if the expression type is different that the expected type coerce the value
|
||||||
selectionType != null && selectionType.getSingleJdbcMapping().getJdbcJavaType() != getJdbcMapping().getJdbcJavaType()
|
selectionType != null && selectionType.getSingleJdbcMapping().getJdbcJavaType() != getJdbcMapping().getJdbcJavaType(),
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.metamodel.mapping.CollectionPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
@ -66,6 +67,11 @@ public class BasicValuedCollectionPart
|
||||||
return nature;
|
return nature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PluralAttributeMapping getCollectionAttribute() {
|
||||||
|
return collectionDescriptor.getAttributeMapping();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MappingType getPartMappingType() {
|
public MappingType getPartMappingType() {
|
||||||
return selectableMapping.getJdbcMapping()::getJavaTypeDescriptor;
|
return selectableMapping.getJdbcMapping()::getJavaTypeDescriptor;
|
||||||
|
@ -168,7 +174,9 @@ public class BasicValuedCollectionPart
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
selectableMapping.getJdbcMapping(),
|
selectableMapping.getJdbcMapping(),
|
||||||
navigablePath
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +288,8 @@ public class BasicValuedCollectionPart
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
creationState
|
creationState,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
|
@ -65,6 +66,11 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
||||||
return Nature.ID;
|
return Nature.ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PluralAttributeMapping getCollectionAttribute() {
|
||||||
|
return collectionDescriptor.getAttributeMapping();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getContainingTableExpression() {
|
public String getContainingTableExpression() {
|
||||||
return containingTableName;
|
return containingTableName;
|
||||||
|
@ -278,7 +284,8 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
creationState
|
creationState,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +312,9 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
null,
|
null,
|
||||||
type,
|
type,
|
||||||
collectionPath
|
collectionPath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,8 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
||||||
declaringModelPart,
|
declaringModelPart,
|
||||||
tableName,
|
tableName,
|
||||||
metaColumn.getText( dialect ),
|
metaColumn.getText( dialect ),
|
||||||
|
metaColumn.getCustomReadExpression(),
|
||||||
|
metaColumn.getCustomWriteExpression(),
|
||||||
metaColumn.getSqlType(),
|
metaColumn.getSqlType(),
|
||||||
metaColumn.getLength(),
|
metaColumn.getLength(),
|
||||||
metaColumn.getPrecision(),
|
metaColumn.getPrecision(),
|
||||||
|
@ -99,6 +101,8 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
||||||
declaringModelPart,
|
declaringModelPart,
|
||||||
tableName,
|
tableName,
|
||||||
keyColumn.getText( dialect ),
|
keyColumn.getText( dialect ),
|
||||||
|
keyColumn.getCustomReadExpression(),
|
||||||
|
keyColumn.getCustomWriteExpression(),
|
||||||
keyColumn.getSqlType(),
|
keyColumn.getSqlType(),
|
||||||
keyColumn.getLength(),
|
keyColumn.getLength(),
|
||||||
keyColumn.getPrecision(),
|
keyColumn.getPrecision(),
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
@ -80,6 +81,11 @@ public class DiscriminatedCollectionPart implements DiscriminatedAssociationMode
|
||||||
return nature;
|
return nature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PluralAttributeMapping getCollectionAttribute() {
|
||||||
|
return collectionDescriptor.getAttributeMapping();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DiscriminatorMapping getDiscriminatorMapping() {
|
public DiscriminatorMapping getDiscriminatorMapping() {
|
||||||
return associationMapping.getDiscriminatorPart();
|
return associationMapping.getDiscriminatorPart();
|
||||||
|
|
|
@ -292,7 +292,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
||||||
case STRUCT_TABLE:
|
case STRUCT_TABLE:
|
||||||
isArray = true;
|
isArray = true;
|
||||||
aggregateSqlTypeCode = STRUCT;
|
aggregateSqlTypeCode = STRUCT;
|
||||||
structTypeName = bootDescriptor.getStructName();
|
structTypeName = bootDescriptor.getStructName().render();
|
||||||
if ( structTypeName == null ) {
|
if ( structTypeName == null ) {
|
||||||
final String arrayTypeName = aggregateColumn.getSqlType( creationContext.getMetadata() );
|
final String arrayTypeName = aggregateColumn.getSqlType( creationContext.getMetadata() );
|
||||||
if ( arrayTypeName.endsWith( " array" ) ) {
|
if ( arrayTypeName.endsWith( " array" ) ) {
|
||||||
|
@ -322,7 +322,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
||||||
);
|
);
|
||||||
// Register the resolved type under its struct name and java class name
|
// Register the resolved type under its struct name and java class name
|
||||||
if ( bootDescriptor.getStructName() != null ) {
|
if ( bootDescriptor.getStructName() != null ) {
|
||||||
basicTypeRegistry.register( basicType, bootDescriptor.getStructName() );
|
basicTypeRegistry.register( basicType, bootDescriptor.getStructName().render() );
|
||||||
basicTypeRegistry.register( basicType, getMappedJavaType().getJavaTypeClass().getName() );
|
basicTypeRegistry.register( basicType, getMappedJavaType().getJavaTypeClass().getName() );
|
||||||
}
|
}
|
||||||
final BasicValue basicValue = (BasicValue) aggregateColumn.getValue();
|
final BasicValue basicValue = (BasicValue) aggregateColumn.getValue();
|
||||||
|
|
|
@ -94,6 +94,11 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
||||||
this.sqlAliasStem = sqlAliasStem;
|
this.sqlAliasStem = sqlAliasStem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PluralAttributeMapping getCollectionAttribute() {
|
||||||
|
return collectionDescriptor.getAttributeMapping();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> DomainResult<T> createDomainResult(
|
public <T> DomainResult<T> createDomainResult(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
|
|
@ -108,7 +108,9 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping {
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
rowIdType,
|
rowIdType,
|
||||||
navigablePath
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -263,7 +263,8 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
creationState,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +280,9 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
versionBasicType,
|
versionBasicType,
|
||||||
navigablePath
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -384,8 +384,10 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
null,
|
null,
|
||||||
selectableMapping.getJdbcMapping(),
|
selectableMapping.getJdbcMapping(),
|
||||||
|
navigablePath,
|
||||||
// if the expression type is different that the expected type coerce the value
|
// if the expression type is different that the expected type coerce the value
|
||||||
selectionType != null && selectionType.getSingleJdbcMapping().getJdbcJavaType() != javaType
|
selectionType != null && selectionType.getSingleJdbcMapping().getJdbcJavaType() != javaType,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,14 @@ public class SoftDeleteMappingImpl implements SoftDeleteMapping {
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, creationState );
|
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, creationState );
|
||||||
return new BasicResult<>( sqlSelection.getValuesArrayPosition(), resultVariable, getJdbcMapping() );
|
return new BasicResult<>(
|
||||||
|
sqlSelection.getValuesArrayPosition(),
|
||||||
|
resultVariable,
|
||||||
|
getJdbcMapping(),
|
||||||
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqlSelection resolveSqlSelection(
|
private SqlSelection resolveSqlSelection(
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
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.sql.results.graph.basic.BasicResultAssembler;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
|
@ -69,7 +70,10 @@ public class ScalarDomainResultBuilder<T> implements ResultBuilder {
|
||||||
return new BasicResult<>(
|
return new BasicResult<>(
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
null,
|
null,
|
||||||
( (BasicType<?>) sqlSelection.getExpressionType() )
|
(BasicType<?>) sqlSelection.getExpressionType(),
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -218,7 +218,9 @@ public class AnonymousTupleBasicValuedModelPart implements OwnedValuedModelPart,
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
navigablePath
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +272,8 @@ public class AnonymousTupleBasicValuedModelPart implements OwnedValuedModelPart,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
creationState,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||||
|
import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
|
||||||
import org.hibernate.sql.results.graph.entity.EntityResult;
|
import org.hibernate.sql.results.graph.entity.EntityResult;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
|
||||||
|
@ -328,7 +329,10 @@ public class ResultSetMappingImpl implements ResultSetMapping {
|
||||||
return new BasicResult(
|
return new BasicResult(
|
||||||
valuesArrayPosition,
|
valuesArrayPosition,
|
||||||
name,
|
name,
|
||||||
jdbcMapping
|
jdbcMapping,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,7 @@ import org.hibernate.query.results.ResultsHelper;
|
||||||
import org.hibernate.spi.NavigablePath;
|
import org.hibernate.spi.NavigablePath;
|
||||||
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
||||||
import org.hibernate.query.results.ResultBuilder;
|
import org.hibernate.query.results.ResultBuilder;
|
||||||
import org.hibernate.query.results.ResultSetMappingSqlSelection;
|
|
||||||
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
|
@ -24,7 +22,6 @@ import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||||
|
|
||||||
import static org.hibernate.query.results.ResultsHelper.impl;
|
import static org.hibernate.query.results.ResultsHelper.impl;
|
||||||
import static org.hibernate.query.results.ResultsHelper.jdbcPositionToValuesArrayPosition;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CompleteResultBuilder for basic-valued ModelParts
|
* CompleteResultBuilder for basic-valued ModelParts
|
||||||
|
@ -93,7 +90,10 @@ public class CompleteResultBuilderBasicModelPart
|
||||||
return new BasicResult<>(
|
return new BasicResult<>(
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
columnAlias,
|
columnAlias,
|
||||||
modelPart.getJdbcMapping()
|
modelPart.getJdbcMapping(),
|
||||||
|
navigablePath,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,10 @@ public class CompleteResultBuilderBasicValuedConverted<O,R> implements CompleteR
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
columnName,
|
columnName,
|
||||||
valueConverter.getDomainJavaType(),
|
valueConverter.getDomainJavaType(),
|
||||||
valueConverter
|
valueConverter,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,10 @@ public class CompleteResultBuilderBasicValuedStandard implements CompleteResultB
|
||||||
return new BasicResult<>(
|
return new BasicResult<>(
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
columnName,
|
columnName,
|
||||||
jdbcMapping
|
jdbcMapping,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
import org.hibernate.sql.results.graph.FetchParent;
|
||||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||||
|
import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,7 +70,9 @@ public class DelayedFetchBuilderBasicPart
|
||||||
null,
|
null,
|
||||||
FetchTiming.DELAYED,
|
FetchTiming.DELAYED,
|
||||||
isEnhancedForLazyLoading,
|
isEnhancedForLazyLoading,
|
||||||
domainResultCreationState
|
domainResultCreationState,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
||||||
import org.hibernate.query.NativeQuery;
|
import org.hibernate.query.NativeQuery;
|
||||||
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
||||||
import org.hibernate.query.results.ResultSetMappingSqlSelection;
|
import org.hibernate.query.results.ResultSetMappingSqlSelection;
|
||||||
import org.hibernate.query.results.ResultsHelper;
|
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
|
@ -103,7 +102,10 @@ public class DynamicResultBuilderAttribute implements DynamicResultBuilder, Nati
|
||||||
return new BasicResult<>(
|
return new BasicResult<>(
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
columnAlias,
|
columnAlias,
|
||||||
attributeMapping.getJdbcMapping()
|
attributeMapping.getJdbcMapping(),
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,10 @@ public class DynamicResultBuilderBasicConverted<O,R> implements DynamicResultBui
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
columnAlias,
|
columnAlias,
|
||||||
basicValueConverter.getDomainJavaType(),
|
basicValueConverter.getDomainJavaType(),
|
||||||
basicValueConverter
|
basicValueConverter,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,15 @@ public class DynamicResultBuilderBasicStandard implements DynamicResultBuilderBa
|
||||||
// StandardRowReader expects there to be a JavaType as part of the ResultAssembler.
|
// StandardRowReader expects there to be a JavaType as part of the ResultAssembler.
|
||||||
assert javaType != null;
|
assert javaType != null;
|
||||||
|
|
||||||
return new BasicResult( sqlSelection.getValuesArrayPosition(), resultAlias, javaType, converter );
|
return new BasicResult(
|
||||||
|
sqlSelection.getValuesArrayPosition(),
|
||||||
|
resultAlias,
|
||||||
|
javaType,
|
||||||
|
converter,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,7 +17,6 @@ import org.hibernate.query.results.BasicValuedFetchBuilder;
|
||||||
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
||||||
import org.hibernate.query.results.FetchBuilder;
|
import org.hibernate.query.results.FetchBuilder;
|
||||||
import org.hibernate.query.results.ResultsHelper;
|
import org.hibernate.query.results.ResultsHelper;
|
||||||
import org.hibernate.query.results.ResultSetMappingSqlSelection;
|
|
||||||
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
|
@ -28,7 +27,6 @@ import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||||
|
|
||||||
import static org.hibernate.query.results.ResultsHelper.impl;
|
import static org.hibernate.query.results.ResultsHelper.impl;
|
||||||
import static org.hibernate.query.results.ResultsHelper.jdbcPositionToValuesArrayPosition;
|
|
||||||
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
|
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,7 +116,8 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, BasicVal
|
||||||
fetchPath,
|
fetchPath,
|
||||||
fetchable,
|
fetchable,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
domainResultCreationState
|
domainResultCreationState,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,10 @@ public class SelfRenderingFunctionSqlAstExpression
|
||||||
.getValuesArrayPosition(),
|
.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
type == null ? null : type.getExpressibleJavaType(),
|
type == null ? null : type.getExpressibleJavaType(),
|
||||||
converter
|
converter,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ 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.sql.results.graph.basic.BasicResultAssembler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around a basic {@link Expression} that produces a {@link BasicResult} as domain result.
|
* A wrapper around a basic {@link Expression} that produces a {@link BasicResult} as domain result.
|
||||||
|
@ -33,7 +34,9 @@ public class ExpressionDomainResultProducer implements DomainResultProducer<Obje
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
expression.getExpressionType().getSingleJdbcMapping(),
|
expression.getExpressionType().getSingleJdbcMapping(),
|
||||||
null
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ import org.hibernate.sql.exec.spi.JdbcOperationQueryMutation;
|
||||||
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||||
|
import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
|
||||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||||
import org.hibernate.type.descriptor.ValueBinder;
|
import org.hibernate.type.descriptor.ValueBinder;
|
||||||
|
@ -402,7 +403,8 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
||||||
null,
|
null,
|
||||||
identifierMapping,
|
identifierMapping,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
null
|
null,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -105,13 +105,16 @@ public class SqlAstQueryPartProcessingStateImpl
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException( "Illegal expression passed for nested fetching: " + expression );
|
throw new IllegalArgumentException( "Illegal expression passed for nested fetching: " + expression );
|
||||||
}
|
}
|
||||||
return expression.createSqlSelection(
|
final int selectableIndex = nestingFetchParent.getReferencedMappingType().getSelectableIndex( selectableName );
|
||||||
-1,
|
if ( selectableIndex != -1 ) {
|
||||||
nestingFetchParent.getReferencedMappingType().getSelectableIndex( selectableName ),
|
return expression.createSqlSelection(
|
||||||
javaType,
|
-1,
|
||||||
true,
|
selectableIndex,
|
||||||
typeConfiguration
|
javaType,
|
||||||
);
|
true,
|
||||||
|
typeConfiguration
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
final Map<Expression, Object> selectionMap;
|
final Map<Expression, Object> selectionMap;
|
||||||
if ( deduplicateSelectionItems ) {
|
if ( deduplicateSelectionItems ) {
|
||||||
|
|
|
@ -108,7 +108,10 @@ public class SqmParameterInterpretation implements Expression, DomainResultProdu
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
resultVariable,
|
resultVariable,
|
||||||
jdbcMapping.getMappedJavaType(),
|
jdbcMapping.getMappedJavaType(),
|
||||||
converter
|
converter,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,26 +38,6 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
||||||
|
|
||||||
private final FetchTiming fetchTiming;
|
private final FetchTiming fetchTiming;
|
||||||
|
|
||||||
public BasicFetch(
|
|
||||||
int valuesArrayPosition,
|
|
||||||
FetchParent fetchParent,
|
|
||||||
NavigablePath fetchablePath,
|
|
||||||
BasicValuedModelPart valuedMapping,
|
|
||||||
FetchTiming fetchTiming,
|
|
||||||
DomainResultCreationState creationState) {
|
|
||||||
//noinspection unchecked
|
|
||||||
this(
|
|
||||||
valuesArrayPosition,
|
|
||||||
fetchParent,
|
|
||||||
fetchablePath,
|
|
||||||
valuedMapping,
|
|
||||||
(BasicValueConverter<T, ?>) valuedMapping.getJdbcMapping().getValueConverter(),
|
|
||||||
fetchTiming,
|
|
||||||
true,
|
|
||||||
creationState
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicFetch(
|
public BasicFetch(
|
||||||
int valuesArrayPosition,
|
int valuesArrayPosition,
|
||||||
FetchParent fetchParent,
|
FetchParent fetchParent,
|
||||||
|
@ -65,7 +45,7 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
||||||
BasicValuedModelPart valuedMapping,
|
BasicValuedModelPart valuedMapping,
|
||||||
FetchTiming fetchTiming,
|
FetchTiming fetchTiming,
|
||||||
DomainResultCreationState creationState,
|
DomainResultCreationState creationState,
|
||||||
boolean coerceResultType) {
|
boolean unwrapRowProcessingState) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
this(
|
this(
|
||||||
valuesArrayPosition,
|
valuesArrayPosition,
|
||||||
|
@ -76,49 +56,8 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
true,
|
true,
|
||||||
creationState,
|
creationState,
|
||||||
coerceResultType
|
false,
|
||||||
);
|
unwrapRowProcessingState
|
||||||
}
|
|
||||||
|
|
||||||
public BasicFetch(
|
|
||||||
int valuesArrayPosition,
|
|
||||||
FetchParent fetchParent,
|
|
||||||
NavigablePath fetchablePath,
|
|
||||||
BasicValuedModelPart valuedMapping,
|
|
||||||
BasicValueConverter<T, ?> valueConverter,
|
|
||||||
FetchTiming fetchTiming,
|
|
||||||
DomainResultCreationState creationState) {
|
|
||||||
this(
|
|
||||||
valuesArrayPosition,
|
|
||||||
fetchParent,
|
|
||||||
fetchablePath,
|
|
||||||
valuedMapping,
|
|
||||||
valueConverter,
|
|
||||||
fetchTiming,
|
|
||||||
true,
|
|
||||||
creationState
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicFetch(
|
|
||||||
int valuesArrayPosition,
|
|
||||||
FetchParent fetchParent,
|
|
||||||
NavigablePath fetchablePath,
|
|
||||||
BasicValuedModelPart valuedMapping,
|
|
||||||
BasicValueConverter<T, ?> valueConverter,
|
|
||||||
FetchTiming fetchTiming,
|
|
||||||
boolean canBasicPartFetchBeDelayed,
|
|
||||||
DomainResultCreationState creationState) {
|
|
||||||
this(
|
|
||||||
valuesArrayPosition,
|
|
||||||
fetchParent,
|
|
||||||
fetchablePath,
|
|
||||||
valuedMapping,
|
|
||||||
valueConverter,
|
|
||||||
fetchTiming,
|
|
||||||
canBasicPartFetchBeDelayed,
|
|
||||||
creationState,
|
|
||||||
false
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +70,8 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
||||||
FetchTiming fetchTiming,
|
FetchTiming fetchTiming,
|
||||||
boolean canBasicPartFetchBeDelayed,
|
boolean canBasicPartFetchBeDelayed,
|
||||||
DomainResultCreationState creationState,
|
DomainResultCreationState creationState,
|
||||||
boolean coerceResultType) {
|
boolean coerceResultType,
|
||||||
|
boolean unwrapRowProcessingState) {
|
||||||
this.navigablePath = fetchablePath;
|
this.navigablePath = fetchablePath;
|
||||||
|
|
||||||
this.fetchParent = fetchParent;
|
this.fetchParent = fetchParent;
|
||||||
|
@ -149,10 +89,10 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (coerceResultType) {
|
if (coerceResultType) {
|
||||||
this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
|
this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter, unwrapRowProcessingState );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
|
this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter, unwrapRowProcessingState );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,9 @@ public class BasicResult<T> implements DomainResult<T>, BasicResultGraphNode<T>
|
||||||
jdbcValuesArrayPosition,
|
jdbcValuesArrayPosition,
|
||||||
resultVariable,
|
resultVariable,
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
null
|
null,
|
||||||
|
false,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,81 +50,38 @@ public class BasicResult<T> implements DomainResult<T>, BasicResultGraphNode<T>
|
||||||
int jdbcValuesArrayPosition,
|
int jdbcValuesArrayPosition,
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
JdbcMapping jdbcMapping,
|
JdbcMapping jdbcMapping,
|
||||||
boolean coerceResultType) {
|
NavigablePath navigablePath,
|
||||||
|
boolean coerceResultType,
|
||||||
|
boolean unwrapRowProcessingState) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
this(
|
this(
|
||||||
jdbcValuesArrayPosition,
|
jdbcValuesArrayPosition,
|
||||||
resultVariable,
|
resultVariable,
|
||||||
jdbcMapping.getJavaTypeDescriptor(),
|
jdbcMapping.getJavaTypeDescriptor(),
|
||||||
jdbcMapping.getValueConverter(),
|
jdbcMapping.getValueConverter(),
|
||||||
null,
|
navigablePath,
|
||||||
coerceResultType
|
coerceResultType,
|
||||||
|
unwrapRowProcessingState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BasicResult(
|
|
||||||
int jdbcValuesArrayPosition,
|
|
||||||
String resultVariable,
|
|
||||||
JdbcMapping jdbcMapping,
|
|
||||||
NavigablePath navigablePath) {
|
|
||||||
//noinspection unchecked
|
|
||||||
this(
|
|
||||||
jdbcValuesArrayPosition,
|
|
||||||
resultVariable,
|
|
||||||
(JavaType<T>) jdbcMapping.getJavaTypeDescriptor(),
|
|
||||||
(BasicValueConverter<T, ?>) jdbcMapping.getValueConverter(),
|
|
||||||
navigablePath
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicResult(
|
|
||||||
int jdbcValuesArrayPosition,
|
|
||||||
String resultVariable,
|
|
||||||
JavaType<T> javaType) {
|
|
||||||
this( jdbcValuesArrayPosition, resultVariable, javaType, null, null );
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicResult(
|
|
||||||
int jdbcValuesArrayPosition,
|
|
||||||
String resultVariable,
|
|
||||||
JavaType<T> javaType,
|
|
||||||
NavigablePath navigablePath) {
|
|
||||||
this( jdbcValuesArrayPosition, resultVariable, javaType, null, navigablePath );
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicResult(
|
|
||||||
int valuesArrayPosition,
|
|
||||||
String resultVariable,
|
|
||||||
JavaType<T> javaType,
|
|
||||||
BasicValueConverter<T,?> valueConverter) {
|
|
||||||
this( valuesArrayPosition, resultVariable, javaType, valueConverter, null );
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicResult(
|
|
||||||
int valuesArrayPosition,
|
|
||||||
String resultVariable,
|
|
||||||
JavaType<T> javaType,
|
|
||||||
BasicValueConverter<T,?> valueConverter,
|
|
||||||
NavigablePath navigablePath) {
|
|
||||||
this( valuesArrayPosition, resultVariable, javaType, valueConverter, navigablePath, false );
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicResult(
|
public BasicResult(
|
||||||
int valuesArrayPosition,
|
int valuesArrayPosition,
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
JavaType<T> javaType,
|
JavaType<T> javaType,
|
||||||
BasicValueConverter<T,?> valueConverter,
|
BasicValueConverter<T,?> valueConverter,
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
boolean coerceResultType) {
|
boolean coerceResultType,
|
||||||
|
boolean unwrapRowProcessingState) {
|
||||||
this.resultVariable = resultVariable;
|
this.resultVariable = resultVariable;
|
||||||
this.javaType = javaType;
|
this.javaType = javaType;
|
||||||
this.navigablePath = navigablePath;
|
this.navigablePath = navigablePath;
|
||||||
|
|
||||||
if ( coerceResultType ) {
|
if ( coerceResultType ) {
|
||||||
this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
|
this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter, unwrapRowProcessingState );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
|
this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter, unwrapRowProcessingState );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,26 +29,30 @@ public class BasicResultAssembler<J> implements DomainResultAssembler<J> {
|
||||||
protected final int valuesArrayPosition;
|
protected final int valuesArrayPosition;
|
||||||
protected final JavaType<J> assembledJavaType;
|
protected final JavaType<J> assembledJavaType;
|
||||||
private final BasicValueConverter<J,?> valueConverter;
|
private final BasicValueConverter<J,?> valueConverter;
|
||||||
|
private final boolean unwrapRowProcessingState;
|
||||||
|
|
||||||
public BasicResultAssembler(
|
public BasicResultAssembler(int valuesArrayPosition, JavaType<J> assembledJavaType) {
|
||||||
int valuesArrayPosition,
|
this( valuesArrayPosition, assembledJavaType, null, false );
|
||||||
JavaType<J> assembledJavaType) {
|
|
||||||
this( valuesArrayPosition, assembledJavaType, null );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BasicResultAssembler(
|
public BasicResultAssembler(
|
||||||
int valuesArrayPosition,
|
int valuesArrayPosition,
|
||||||
JavaType<J> assembledJavaType,
|
JavaType<J> assembledJavaType,
|
||||||
BasicValueConverter<J, ?> valueConverter) {
|
BasicValueConverter<J, ?> valueConverter,
|
||||||
|
boolean unwrapRowProcessingState) {
|
||||||
this.valuesArrayPosition = valuesArrayPosition;
|
this.valuesArrayPosition = valuesArrayPosition;
|
||||||
this.assembledJavaType = assembledJavaType;
|
this.assembledJavaType = assembledJavaType;
|
||||||
this.valueConverter = valueConverter;
|
this.valueConverter = valueConverter;
|
||||||
|
this.unwrapRowProcessingState = unwrapRowProcessingState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access to the raw value (unconverted, if a converter applied)
|
* Access to the raw value (unconverted, if a converter applied)
|
||||||
*/
|
*/
|
||||||
public Object extractRawValue(RowProcessingState rowProcessingState) {
|
public Object extractRawValue(RowProcessingState rowProcessingState) {
|
||||||
|
if ( unwrapRowProcessingState ) {
|
||||||
|
rowProcessingState = rowProcessingState.unwrap();
|
||||||
|
}
|
||||||
return rowProcessingState.getJdbcValue( valuesArrayPosition );
|
return rowProcessingState.getJdbcValue( valuesArrayPosition );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,9 @@ public class CoercingResultAssembler<J> extends BasicResultAssembler<J> {
|
||||||
public CoercingResultAssembler(
|
public CoercingResultAssembler(
|
||||||
int valuesArrayPosition,
|
int valuesArrayPosition,
|
||||||
JavaType<J> assembledJavaType,
|
JavaType<J> assembledJavaType,
|
||||||
BasicValueConverter<J, ?> valueConverter) {
|
BasicValueConverter<J, ?> valueConverter,
|
||||||
super( valuesArrayPosition, assembledJavaType, valueConverter );
|
boolean nestedInAggregateComponent) {
|
||||||
|
super( valuesArrayPosition, assembledJavaType, valueConverter, nestedInAggregateComponent );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,7 +32,7 @@ public class CoercingResultAssembler<J> extends BasicResultAssembler<J> {
|
||||||
@Override
|
@Override
|
||||||
public Object extractRawValue(RowProcessingState rowProcessingState) {
|
public Object extractRawValue(RowProcessingState rowProcessingState) {
|
||||||
return assembledJavaType.coerce(
|
return assembledJavaType.coerce(
|
||||||
rowProcessingState.getJdbcValue( valuesArrayPosition ),
|
super.extractRawValue( rowProcessingState ),
|
||||||
rowProcessingState.getSession()
|
rowProcessingState.getSession()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,8 @@ public class EmbeddableExpressionResultImpl<T> extends AbstractFetchParent imple
|
||||||
resolveNavigablePath( attribute ),
|
resolveNavigablePath( attribute ),
|
||||||
attribute,
|
attribute,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
creationState
|
creationState,
|
||||||
|
!sqlSelection.isVirtual()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,11 @@ public class NestedRowProcessingState extends BaseExecutionContext implements Ro
|
||||||
return jdbcValue == null ? null : jdbcValue[position];
|
return jdbcValue == null ? null : jdbcValue[position];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RowProcessingState unwrap() {
|
||||||
|
return processingState;
|
||||||
|
}
|
||||||
|
|
||||||
// -- delegate the rest
|
// -- delegate the rest
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -68,4 +68,12 @@ public interface RowProcessingState extends ExecutionContext {
|
||||||
finishRowProcessing();
|
finishRowProcessing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this is a row processing state for aggregate components,
|
||||||
|
* this will return the underlying row processing state.
|
||||||
|
*/
|
||||||
|
default RowProcessingState unwrap() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class BooleanJavaType extends AbstractClassJavaType<Boolean> implements
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Boolean.class.isAssignableFrom( type ) ) {
|
if ( Boolean.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||||
return (X) value;
|
return (X) value;
|
||||||
}
|
}
|
||||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
if ( Byte.class.isAssignableFrom( type ) ) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class ByteJavaType extends AbstractClassJavaType<Byte>
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
if ( Byte.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||||
return (X) value;
|
return (X) value;
|
||||||
}
|
}
|
||||||
if ( Short.class.isAssignableFrom( type ) ) {
|
if ( Short.class.isAssignableFrom( type ) ) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class CharacterJavaType extends AbstractClassJavaType<Character> implemen
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Character.class.isAssignableFrom( type ) ) {
|
if ( Character.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||||
return (X) value;
|
return (X) value;
|
||||||
}
|
}
|
||||||
if ( String.class.isAssignableFrom( type ) ) {
|
if ( String.class.isAssignableFrom( type ) ) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class DoubleJavaType extends AbstractClassJavaType<Double> implements
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Double.class.isAssignableFrom( type ) ) {
|
if ( Double.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||||
return (X) value;
|
return (X) value;
|
||||||
}
|
}
|
||||||
if ( Float.class.isAssignableFrom( type ) ) {
|
if ( Float.class.isAssignableFrom( type ) ) {
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class FloatJavaType extends AbstractClassJavaType<Float> implements Primi
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Float.class.isAssignableFrom( type ) ) {
|
if ( Float.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||||
return (X) value;
|
return (X) value;
|
||||||
}
|
}
|
||||||
if ( Double.class.isAssignableFrom( type ) ) {
|
if ( Double.class.isAssignableFrom( type ) ) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class IntegerJavaType extends AbstractClassJavaType<Integer>
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Integer.class.isAssignableFrom( type ) ) {
|
if ( Integer.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||||
return (X) value;
|
return (X) value;
|
||||||
}
|
}
|
||||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
if ( Byte.class.isAssignableFrom( type ) ) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class LongJavaType extends AbstractClassJavaType<Long>
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Long.class.isAssignableFrom( type ) ) {
|
if ( Long.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||||
return (X) value;
|
return (X) value;
|
||||||
}
|
}
|
||||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
if ( Byte.class.isAssignableFrom( type ) ) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class ShortJavaType extends AbstractClassJavaType<Short>
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Short.class.isAssignableFrom( type ) ) {
|
if ( Short.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||||
return (X) value;
|
return (X) value;
|
||||||
}
|
}
|
||||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
if ( Byte.class.isAssignableFrom( type ) ) {
|
||||||
|
|
|
@ -20,7 +20,6 @@ import org.hibernate.dialect.StructHelper;
|
||||||
import org.hibernate.engine.jdbc.Size;
|
import org.hibernate.engine.jdbc.Size;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
|
||||||
import org.hibernate.type.BasicPluralType;
|
import org.hibernate.type.BasicPluralType;
|
||||||
import org.hibernate.type.descriptor.ValueBinder;
|
import org.hibernate.type.descriptor.ValueBinder;
|
||||||
import org.hibernate.type.descriptor.ValueExtractor;
|
import org.hibernate.type.descriptor.ValueExtractor;
|
||||||
|
@ -107,23 +106,58 @@ public class ArrayJdbcType implements JdbcType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getPreferredJavaTypeClass(WrapperOptions options) {
|
public Class<?> getPreferredJavaTypeClass(WrapperOptions options) {
|
||||||
return java.sql.Array.class;
|
return Object[].class;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object[] getArray(BasicBinder<?> binder, Object value, WrapperOptions options) throws SQLException {
|
protected String getElementTypeName(JavaType<?> javaType, SharedSessionContractImplementor session) {
|
||||||
|
// TODO: ideally, we would have the actual size or the actual type/column accessible
|
||||||
|
// this is something that we would need for supporting composite types anyway
|
||||||
|
if ( elementJdbcType instanceof StructJdbcType ) {
|
||||||
|
return ( (StructJdbcType) elementJdbcType ).getStructTypeName();
|
||||||
|
}
|
||||||
|
final JavaType<?> elementJavaType;
|
||||||
|
if ( javaType instanceof ByteArrayJavaType ) {
|
||||||
|
// Special handling needed for Byte[], because that would conflict with the VARBINARY mapping
|
||||||
|
elementJavaType = ByteJavaType.INSTANCE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elementJavaType = ( (BasicPluralJavaType<?>) javaType ).getElementJavaType();
|
||||||
|
}
|
||||||
|
final Size size = session.getJdbcServices()
|
||||||
|
.getDialect()
|
||||||
|
.getSizeStrategy()
|
||||||
|
.resolveSize( elementJdbcType, elementJavaType, null, null, null );
|
||||||
|
final DdlTypeRegistry ddlTypeRegistry = session.getTypeConfiguration().getDdlTypeRegistry();
|
||||||
|
final String typeName = ddlTypeRegistry.getDescriptor( elementJdbcType.getDdlTypeCode() )
|
||||||
|
.getTypeName( size, new BasicTypeImpl<>( elementJavaType, elementJdbcType), ddlTypeRegistry );
|
||||||
|
int cutIndex = typeName.indexOf( '(' );
|
||||||
|
if ( cutIndex > 0 ) {
|
||||||
|
// getTypeName for this case required length, etc, parameters.
|
||||||
|
// Cut them out and use database defaults.
|
||||||
|
return typeName.substring( 0, cutIndex );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object[] getArray(
|
||||||
|
BasicBinder<?> binder,
|
||||||
|
ValueBinder<Object> elementBinder,
|
||||||
|
Object value,
|
||||||
|
WrapperOptions options) throws SQLException {
|
||||||
final JdbcType elementJdbcType = ( (ArrayJdbcType) binder.getJdbcType() ).getElementJdbcType();
|
final JdbcType elementJdbcType = ( (ArrayJdbcType) binder.getJdbcType() ).getElementJdbcType();
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
final JavaType<Object> javaType = (JavaType<Object>) binder.getJavaType();
|
final JavaType<Object> javaType = (JavaType<Object>) binder.getJavaType();
|
||||||
if ( elementJdbcType instanceof AggregateJdbcType ) {
|
if ( elementJdbcType instanceof AggregateJdbcType ) {
|
||||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) elementJdbcType;
|
final Object[] domainObjects = javaType.unwrap(
|
||||||
final Object[] domainObjects = ( javaType ).unwrap(
|
|
||||||
value,
|
value,
|
||||||
Object[].class,
|
Object[].class,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
final Object[] objects = new Object[domainObjects.length];
|
final Object[] objects = new Object[domainObjects.length];
|
||||||
for ( int i = 0; i < domainObjects.length; i++ ) {
|
for ( int i = 0; i < domainObjects.length; i++ ) {
|
||||||
objects[i] = aggregateJdbcType.createJdbcValue( domainObjects[i], options );
|
objects[i] = elementBinder.getBindValue( domainObjects[i], options );
|
||||||
}
|
}
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
@ -174,6 +208,8 @@ public class ArrayJdbcType implements JdbcType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) {
|
public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) {
|
||||||
|
//noinspection unchecked
|
||||||
|
final ValueBinder<Object> elementBinder = elementJdbcType.getBinder( ( (BasicPluralJavaType<Object>) javaTypeDescriptor ).getElementJavaType() );
|
||||||
return new BasicBinder<>( javaTypeDescriptor, this ) {
|
return new BasicBinder<>( javaTypeDescriptor, this ) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -193,48 +229,19 @@ public class ArrayJdbcType implements JdbcType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private java.sql.Array getArray(X value, WrapperOptions options) throws SQLException {
|
@Override
|
||||||
final JdbcType elementJdbcType = ( (ArrayJdbcType) getJdbcType() ).getElementJdbcType();
|
public Object getBindValue(X value, WrapperOptions options) throws SQLException {
|
||||||
final Object[] objects = ArrayJdbcType.this.getArray( this, value, options );
|
return ( (ArrayJdbcType) getJdbcType() ).getArray( this, elementBinder, value, options );
|
||||||
|
|
||||||
final SharedSessionContractImplementor session = options.getSession();
|
|
||||||
final String typeName = getElementTypeName( elementJdbcType, session );
|
|
||||||
return session.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection()
|
|
||||||
.createArrayOf( typeName, objects );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getElementTypeName(JdbcType elementJdbcType, SharedSessionContractImplementor session) {
|
private java.sql.Array getArray(X value, WrapperOptions options) throws SQLException {
|
||||||
// TODO: ideally, we would have the actual size or the actual type/column accessible
|
final ArrayJdbcType arrayJdbcType = (ArrayJdbcType) getJdbcType();
|
||||||
// this is something that we would need for supporting composite types anyway
|
final Object[] objects = arrayJdbcType.getArray( this, elementBinder, value, options );
|
||||||
if ( elementJdbcType instanceof StructJdbcType ) {
|
|
||||||
return ( (StructJdbcType) elementJdbcType ).getStructTypeName();
|
final SharedSessionContractImplementor session = options.getSession();
|
||||||
}
|
final String typeName = arrayJdbcType.getElementTypeName( getJavaType(), session );
|
||||||
final JavaType<X> elementJavaType;
|
return session.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection()
|
||||||
if ( getJavaType() instanceof ByteArrayJavaType ) {
|
.createArrayOf( typeName, objects );
|
||||||
// Special handling needed for Byte[], because that would conflict with the VARBINARY mapping
|
|
||||||
//noinspection unchecked
|
|
||||||
elementJavaType = (JavaType<X>) ByteJavaType.INSTANCE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//noinspection unchecked
|
|
||||||
elementJavaType = ( (BasicPluralJavaType<X>) getJavaType() ).getElementJavaType();
|
|
||||||
}
|
|
||||||
final Size size = session.getJdbcServices()
|
|
||||||
.getDialect()
|
|
||||||
.getSizeStrategy()
|
|
||||||
.resolveSize( elementJdbcType, elementJavaType, null, null, null );
|
|
||||||
final DdlTypeRegistry ddlTypeRegistry = session.getTypeConfiguration().getDdlTypeRegistry();
|
|
||||||
final String typeName = ddlTypeRegistry.getDescriptor( elementJdbcType.getDdlTypeCode() )
|
|
||||||
.getTypeName( size, new BasicTypeImpl<>( elementJavaType, elementJdbcType), ddlTypeRegistry );
|
|
||||||
int cutIndex = typeName.indexOf( '(' );
|
|
||||||
if ( cutIndex > 0 ) {
|
|
||||||
// getTypeName for this case required length, etc, parameters.
|
|
||||||
// Cut them out and use database defaults.
|
|
||||||
return typeName.substring( 0, cutIndex );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return typeName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -266,7 +273,7 @@ public class ArrayJdbcType implements JdbcType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ArrayTypeDescriptor";
|
return "ArrayTypeDescriptor(" + getElementJdbcType().toString() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,18 +20,21 @@ import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.FetchType;
|
import jakarta.persistence.FetchType;
|
||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.OneToMany;
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
@JiraKey( "HHH-15831" )
|
||||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
public class StructComponentCollectionErrorTest {
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructuralArrays.class)
|
||||||
|
public class StructComponentAssociationErrorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@JiraKey( "HHH-15831" )
|
public void testOneToOneMappedBy() {
|
||||||
public void testError1() {
|
|
||||||
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
||||||
try {
|
try {
|
||||||
new MetadataSources( ssr )
|
new MetadataSources( ssr )
|
||||||
|
@ -41,7 +44,7 @@ public class StructComponentCollectionErrorTest {
|
||||||
Assertions.fail( "Expected a failure" );
|
Assertions.fail( "Expected a failure" );
|
||||||
}
|
}
|
||||||
catch (MappingException ex) {
|
catch (MappingException ex) {
|
||||||
assertThat( ex.getMessage(), containsString( "author.favoriteBook" ) );
|
assertThat( ex.getMessage(), containsString( "authors.favoriteBook" ) );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
StandardServiceRegistryBuilder.destroy( ssr );
|
StandardServiceRegistryBuilder.destroy( ssr );
|
||||||
|
@ -56,19 +59,21 @@ public class StructComponentCollectionErrorTest {
|
||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
private Long id;
|
private Long id;
|
||||||
private String title;
|
private String title;
|
||||||
private Person1 author;
|
private Person1[] authors;
|
||||||
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
|
private Book1 favoredBook;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Embeddable
|
@Embeddable
|
||||||
@Struct(name = "person_type")
|
@Struct(name = "person_type")
|
||||||
public static class Person1 {
|
public static class Person1 {
|
||||||
private String name;
|
private String name;
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@OneToOne(mappedBy = "favoredBook", fetch = FetchType.LAZY)
|
||||||
private Book1 favoriteBook;
|
private Book1 favoriteBook;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@JiraKey( "HHH-15831" )
|
public void testOneToManyMappedBy() {
|
||||||
public void testError2() {
|
|
||||||
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
||||||
try {
|
try {
|
||||||
new MetadataSources( ssr )
|
new MetadataSources( ssr )
|
||||||
|
@ -78,7 +83,7 @@ public class StructComponentCollectionErrorTest {
|
||||||
Assertions.fail( "Expected a failure" );
|
Assertions.fail( "Expected a failure" );
|
||||||
}
|
}
|
||||||
catch (MappingException ex) {
|
catch (MappingException ex) {
|
||||||
assertThat( ex.getMessage(), containsString( "author.bookCollection" ) );
|
assertThat( ex.getMessage(), containsString( "authors.bookCollection" ) );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
StandardServiceRegistryBuilder.destroy( ssr );
|
StandardServiceRegistryBuilder.destroy( ssr );
|
||||||
|
@ -93,15 +98,54 @@ public class StructComponentCollectionErrorTest {
|
||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
private Long id;
|
private Long id;
|
||||||
private String title;
|
private String title;
|
||||||
private Person2 author;
|
private Person2[] authors;
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private Book2 mainBook;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Embeddable
|
@Embeddable
|
||||||
@Struct(name = "person_type")
|
@Struct(name = "person_type")
|
||||||
public static class Person2 {
|
public static class Person2 {
|
||||||
private String name;
|
private String name;
|
||||||
@OneToMany
|
@OneToMany(mappedBy = "mainBook")
|
||||||
private List<Book2> bookCollection;
|
private List<Book2> bookCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOneToMany() {
|
||||||
|
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
||||||
|
try {
|
||||||
|
new MetadataSources( ssr )
|
||||||
|
.addAnnotatedClass( Book3.class )
|
||||||
|
.getMetadataBuilder()
|
||||||
|
.build();
|
||||||
|
Assertions.fail( "Expected a failure" );
|
||||||
|
}
|
||||||
|
catch (MappingException ex) {
|
||||||
|
assertThat( ex.getMessage(), containsString( "authors.bookCollection" ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
StandardServiceRegistryBuilder.destroy( ssr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book3 {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Person3[] authors;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct(name = "person_type")
|
||||||
|
public static class Person3 {
|
||||||
|
private String name;
|
||||||
|
@OneToMany
|
||||||
|
private List<Book3> bookCollection;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
package org.hibernate.orm.test.component;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.Any;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||||
|
import org.hibernate.annotations.AnyKeyJavaClass;
|
||||||
|
import org.hibernate.annotations.Struct;
|
||||||
|
|
||||||
|
import org.hibernate.testing.jdbc.SharedDriverManagerTypeCacheClearingIntegrator;
|
||||||
|
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@BootstrapServiceRegistry(
|
||||||
|
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
integrators = SharedDriverManagerTypeCacheClearingIntegrator.class
|
||||||
|
)
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
StructComponentManyToAnyTest.Book.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
|
public class StructComponentManyToAnyTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book1 = new Book();
|
||||||
|
book1.id = 1L;
|
||||||
|
book1.title = "Hibernate 3";
|
||||||
|
book1.author = new Author( "Gavin", null );
|
||||||
|
|
||||||
|
session.save( book1 );
|
||||||
|
|
||||||
|
Book book2 = new Book();
|
||||||
|
book2.id = 2L;
|
||||||
|
book2.title = "Hibernate 6";
|
||||||
|
book2.author = new Author( "Steve", book1 );
|
||||||
|
|
||||||
|
session.save( book2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from Book" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery( "from Book b where b.id = 2", Book.class ).getSingleResult();
|
||||||
|
assertFalse( Hibernate.isInitialized( book.author.getFavoriteBook() ) );
|
||||||
|
assertEquals( "Gavin", book.author.getFavoriteBook().getAuthor().getName() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Author author;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(Author author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct( name = "author_type")
|
||||||
|
public static class Author {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
@Any(fetch = FetchType.LAZY)
|
||||||
|
@AnyKeyJavaClass(Long.class)
|
||||||
|
@AnyDiscriminatorValue(entity = Book.class, discriminator = "B")
|
||||||
|
@JoinColumn(name = "favorite_book_id")
|
||||||
|
@Column(name = "favorite_book_type")
|
||||||
|
private Object favoriteBook;
|
||||||
|
|
||||||
|
public Author() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author(String name, Object favoriteBook) {
|
||||||
|
this.name = name;
|
||||||
|
this.favoriteBook = favoriteBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Book getFavoriteBook() {
|
||||||
|
return (Book) favoriteBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFavoriteBook(Book favoriteBook) {
|
||||||
|
this.favoriteBook = favoriteBook;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
package org.hibernate.orm.test.component;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.Struct;
|
||||||
|
|
||||||
|
import org.hibernate.testing.jdbc.SharedDriverManagerTypeCacheClearingIntegrator;
|
||||||
|
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@BootstrapServiceRegistry(
|
||||||
|
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
integrators = SharedDriverManagerTypeCacheClearingIntegrator.class
|
||||||
|
)
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
StructComponentManyToManyMappedByTest.Book.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
|
public class StructComponentManyToManyMappedByTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book1 = new Book();
|
||||||
|
book1.id = 1L;
|
||||||
|
book1.title = "Main book";
|
||||||
|
book1.author = new Author( "Abc" );
|
||||||
|
|
||||||
|
session.save( book1 );
|
||||||
|
|
||||||
|
Book book2 = new Book();
|
||||||
|
book2.id = 2L;
|
||||||
|
book2.title = "Second book";
|
||||||
|
book2.booksInSeries = Set.of( book1 );
|
||||||
|
book2.author = new Author( "Abc" );
|
||||||
|
|
||||||
|
session.save( book2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from Book" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery( "from Book b where b.id = 1", Book.class ).getSingleResult();
|
||||||
|
assertFalse( Hibernate.isInitialized( book.author.getBooks() ) );
|
||||||
|
assertEquals( "Second book", book.author.getBooks().iterator().next().getTitle() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoin(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery(
|
||||||
|
"from Book b join fetch b.author.books where b.id = 1",
|
||||||
|
Book.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertTrue( Hibernate.isInitialized( book.author.getBooks() ) );
|
||||||
|
assertEquals( "Second book", book.author.getBooks().iterator().next().getTitle() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Author author;
|
||||||
|
@ManyToMany
|
||||||
|
private Set<Book> booksInSeries;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(Author author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Book> getBooksInSeries() {
|
||||||
|
return booksInSeries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBooksInSeries(Set<Book> booksInSeries) {
|
||||||
|
this.booksInSeries = booksInSeries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct( name = "author_type")
|
||||||
|
public static class Author {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
@ManyToMany(mappedBy = "booksInSeries")
|
||||||
|
private Set<Book> books;
|
||||||
|
|
||||||
|
public Author() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Book> getBooks() {
|
||||||
|
return books;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBooks(Set<Book> books) {
|
||||||
|
this.books = books;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
package org.hibernate.orm.test.component;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.Struct;
|
||||||
|
|
||||||
|
import org.hibernate.testing.jdbc.SharedDriverManagerTypeCacheClearingIntegrator;
|
||||||
|
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@BootstrapServiceRegistry(
|
||||||
|
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
integrators = SharedDriverManagerTypeCacheClearingIntegrator.class
|
||||||
|
)
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
StructComponentManyToManyTest.Book.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
|
public class StructComponentManyToManyTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book1 = new Book();
|
||||||
|
book1.id = 1L;
|
||||||
|
book1.title = "Main book";
|
||||||
|
book1.author = new Author( "Abc", null );
|
||||||
|
|
||||||
|
session.save( book1 );
|
||||||
|
|
||||||
|
Book book2 = new Book();
|
||||||
|
book2.id = 2L;
|
||||||
|
book2.title = "Second book";
|
||||||
|
book2.author = new Author( "Abc", book1 );
|
||||||
|
|
||||||
|
session.save( book2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from Book" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery( "from Book b where b.id = 2", Book.class ).getSingleResult();
|
||||||
|
assertFalse( Hibernate.isInitialized( book.author.getBooks() ) );
|
||||||
|
assertEquals( "Main book", book.author.getBooks().iterator().next().getTitle() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoin(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery(
|
||||||
|
"from Book b join fetch b.author.books where b.id = 2",
|
||||||
|
Book.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertTrue( Hibernate.isInitialized( book.author.getBooks() ) );
|
||||||
|
assertEquals( "Main book", book.author.getBooks().iterator().next().getTitle() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Author author;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(Author author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct( name = "author_type")
|
||||||
|
public static class Author {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
@ManyToMany
|
||||||
|
private Set<Book> books;
|
||||||
|
|
||||||
|
public Author() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author(String name, Book book) {
|
||||||
|
this.name = name;
|
||||||
|
this.books = book == null ? null : Set.of( book );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Book> getBooks() {
|
||||||
|
return books;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBooks(Set<Book> books) {
|
||||||
|
this.books = books;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
package org.hibernate.orm.test.component;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.Struct;
|
||||||
|
|
||||||
|
import org.hibernate.testing.jdbc.SharedDriverManagerTypeCacheClearingIntegrator;
|
||||||
|
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@BootstrapServiceRegistry(
|
||||||
|
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
integrators = SharedDriverManagerTypeCacheClearingIntegrator.class
|
||||||
|
)
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
StructComponentManyToOneTest.Book.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
|
public class StructComponentManyToOneTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book1 = new Book();
|
||||||
|
book1.id = 1L;
|
||||||
|
book1.title = "Hibernate 3";
|
||||||
|
book1.author = new Author( "Gavin", null );
|
||||||
|
|
||||||
|
session.save( book1 );
|
||||||
|
|
||||||
|
Book book2 = new Book();
|
||||||
|
book2.id = 2L;
|
||||||
|
book2.title = "Hibernate 6";
|
||||||
|
book2.author = new Author( "Steve", book1 );
|
||||||
|
|
||||||
|
session.save( book2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from Book" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery( "from Book b where b.id = 2", Book.class ).getSingleResult();
|
||||||
|
assertFalse( Hibernate.isInitialized( book.author.getFavoriteBook() ) );
|
||||||
|
assertEquals( "Gavin", book.author.getFavoriteBook().getAuthor().getName() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoin(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery(
|
||||||
|
"from Book b join fetch b.author.favoriteBook where b.id = 2",
|
||||||
|
Book.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertTrue( Hibernate.isInitialized( book.author.getFavoriteBook() ) );
|
||||||
|
assertEquals( "Gavin", book.author.getFavoriteBook().getAuthor().getName() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Author author;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(Author author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct( name = "author_type")
|
||||||
|
public static class Author {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private Book favoriteBook;
|
||||||
|
|
||||||
|
public Author() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author(String name, Book favoriteBook) {
|
||||||
|
this.name = name;
|
||||||
|
this.favoriteBook = favoriteBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Book getFavoriteBook() {
|
||||||
|
return favoriteBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFavoriteBook(Book favoriteBook) {
|
||||||
|
this.favoriteBook = favoriteBook;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
package org.hibernate.orm.test.component;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.Struct;
|
||||||
|
|
||||||
|
import org.hibernate.testing.jdbc.SharedDriverManagerTypeCacheClearingIntegrator;
|
||||||
|
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@BootstrapServiceRegistry(
|
||||||
|
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
integrators = SharedDriverManagerTypeCacheClearingIntegrator.class
|
||||||
|
)
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
StructComponentOneToManyMappedByTest.Book.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
|
public class StructComponentOneToManyMappedByTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book1 = new Book();
|
||||||
|
book1.id = 1L;
|
||||||
|
book1.title = "Main book";
|
||||||
|
book1.author = new Author( "Abc" );
|
||||||
|
|
||||||
|
session.save( book1 );
|
||||||
|
|
||||||
|
Book book2 = new Book();
|
||||||
|
book2.id = 2L;
|
||||||
|
book2.title = "Second book";
|
||||||
|
book2.mainBook = book1;
|
||||||
|
book2.author = new Author( "Abc" );
|
||||||
|
|
||||||
|
session.save( book2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from Book" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery( "from Book b where b.id = 1", Book.class ).getSingleResult();
|
||||||
|
assertFalse( Hibernate.isInitialized( book.author.getBooks() ) );
|
||||||
|
assertEquals( "Second book", book.author.getBooks().iterator().next().getTitle() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoin(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery(
|
||||||
|
"from Book b join fetch b.author.books where b.id = 1",
|
||||||
|
Book.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertTrue( Hibernate.isInitialized( book.author.getBooks() ) );
|
||||||
|
assertEquals( "Second book", book.author.getBooks().iterator().next().getTitle() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Author author;
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private Book mainBook;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(Author author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Book getMainBook() {
|
||||||
|
return mainBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMainBook(Book mainBook) {
|
||||||
|
this.mainBook = mainBook;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct( name = "author_type")
|
||||||
|
public static class Author {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
@OneToMany(mappedBy = "mainBook")
|
||||||
|
private Set<Book> books;
|
||||||
|
|
||||||
|
public Author() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Book> getBooks() {
|
||||||
|
return books;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBooks(Set<Book> books) {
|
||||||
|
this.books = books;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
package org.hibernate.orm.test.component;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.Struct;
|
||||||
|
|
||||||
|
import org.hibernate.testing.jdbc.SharedDriverManagerTypeCacheClearingIntegrator;
|
||||||
|
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@BootstrapServiceRegistry(
|
||||||
|
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
integrators = SharedDriverManagerTypeCacheClearingIntegrator.class
|
||||||
|
)
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
StructComponentOneToManyTest.Book.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
|
public class StructComponentOneToManyTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book1 = new Book();
|
||||||
|
book1.id = 1L;
|
||||||
|
book1.title = "Hibernate 3";
|
||||||
|
book1.author = new Author( "Gavin", null );
|
||||||
|
|
||||||
|
session.save( book1 );
|
||||||
|
|
||||||
|
Book book2 = new Book();
|
||||||
|
book2.id = 2L;
|
||||||
|
book2.title = "Hibernate 6";
|
||||||
|
book2.author = new Author( "Steve", book1 );
|
||||||
|
|
||||||
|
session.save( book2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from Book" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery( "from Book b where b.id = 2", Book.class ).getSingleResult();
|
||||||
|
assertFalse( Hibernate.isInitialized( book.author.getBooks() ) );
|
||||||
|
assertEquals( "Gavin", book.author.getBooks().iterator().next().getAuthor().getName() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoin(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery(
|
||||||
|
"from Book b join fetch b.author.books where b.id = 2",
|
||||||
|
Book.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertTrue( Hibernate.isInitialized( book.author.getBooks() ) );
|
||||||
|
assertEquals( "Gavin", book.author.getBooks().iterator().next().getAuthor().getName() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Author author;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(Author author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct( name = "author_type")
|
||||||
|
public static class Author {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
@OneToMany
|
||||||
|
private Set<Book> books;
|
||||||
|
|
||||||
|
public Author() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author(String name, Book book) {
|
||||||
|
this.name = name;
|
||||||
|
this.books = book == null ? null : Set.of( book );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Book> getBooks() {
|
||||||
|
return books;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBooks(Set<Book> books) {
|
||||||
|
this.books = books;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
package org.hibernate.orm.test.component;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.Struct;
|
||||||
|
|
||||||
|
import org.hibernate.testing.jdbc.SharedDriverManagerTypeCacheClearingIntegrator;
|
||||||
|
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@BootstrapServiceRegistry(
|
||||||
|
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
integrators = SharedDriverManagerTypeCacheClearingIntegrator.class
|
||||||
|
)
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
StructComponentOneToOneMappedByTest.Book.class,
|
||||||
|
StructComponentOneToOneMappedByTest.BookDetails.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
|
public class StructComponentOneToOneMappedByTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = new Book();
|
||||||
|
BookDetails bookDetails = new BookDetails(book, "A nice book");
|
||||||
|
book.id = 1L;
|
||||||
|
book.title = "Hibernate 6";
|
||||||
|
book.author = new Author( "Steve", bookDetails );
|
||||||
|
|
||||||
|
session.save( book );
|
||||||
|
session.save( bookDetails );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from BookDetails" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Book" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery( "from Book b", Book.class ).getSingleResult();
|
||||||
|
// One-to-one mappedBy is eager by default
|
||||||
|
assertTrue( Hibernate.isInitialized( book.author.getDetails() ) );
|
||||||
|
assertEquals( "A nice book", book.author.getDetails().getSummary() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoin(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery(
|
||||||
|
"from Book b join fetch b.author.details",
|
||||||
|
Book.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertTrue( Hibernate.isInitialized( book.author.getDetails() ) );
|
||||||
|
assertEquals( "A nice book", book.author.getDetails().getSummary() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Author author;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(Author author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct( name = "author_type")
|
||||||
|
public static class Author {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
@OneToOne(mappedBy = "book", fetch = FetchType.LAZY)
|
||||||
|
private BookDetails details;
|
||||||
|
|
||||||
|
public Author() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author(String name, BookDetails details) {
|
||||||
|
this.name = name;
|
||||||
|
this.details = details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BookDetails getDetails() {
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetails(BookDetails details) {
|
||||||
|
this.details = details;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "BookDetails")
|
||||||
|
public static class BookDetails {
|
||||||
|
@Id
|
||||||
|
@OneToOne
|
||||||
|
private Book book;
|
||||||
|
private String summary;
|
||||||
|
|
||||||
|
public BookDetails() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BookDetails(Book book, String summary) {
|
||||||
|
this.book = book;
|
||||||
|
this.summary = summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Book getBook() {
|
||||||
|
return book;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBook(Book book) {
|
||||||
|
this.book = book;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSummary() {
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSummary(String summary) {
|
||||||
|
this.summary = summary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
package org.hibernate.orm.test.component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.Struct;
|
||||||
|
|
||||||
|
import org.hibernate.testing.jdbc.SharedDriverManagerTypeCacheClearingIntegrator;
|
||||||
|
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@BootstrapServiceRegistry(
|
||||||
|
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
integrators = SharedDriverManagerTypeCacheClearingIntegrator.class
|
||||||
|
)
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
StructComponentOneToOneTest.Book.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
|
public class StructComponentOneToOneTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book1 = new Book();
|
||||||
|
book1.id = 1L;
|
||||||
|
book1.title = "Hibernate 3";
|
||||||
|
book1.author = new Author( "Gavin", null );
|
||||||
|
|
||||||
|
session.save( book1 );
|
||||||
|
|
||||||
|
Book book2 = new Book();
|
||||||
|
book2.id = 2L;
|
||||||
|
book2.title = "Hibernate 6";
|
||||||
|
book2.author = new Author( "Steve", book1 );
|
||||||
|
|
||||||
|
session.save( book2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from Book" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery( "from Book b where b.id = 2", Book.class ).getSingleResult();
|
||||||
|
assertFalse( Hibernate.isInitialized( book.author.getFavoriteBook() ) );
|
||||||
|
assertEquals( "Gavin", book.author.getFavoriteBook().getAuthor().getName() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoin(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Book book = session.createQuery(
|
||||||
|
"from Book b join fetch b.author.favoriteBook where b.id = 2",
|
||||||
|
Book.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertTrue( Hibernate.isInitialized( book.author.getFavoriteBook() ) );
|
||||||
|
assertEquals( "Gavin", book.author.getFavoriteBook().getAuthor().getName() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Author author;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(Author author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct( name = "author_type")
|
||||||
|
public static class Author {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
|
private Book favoriteBook;
|
||||||
|
|
||||||
|
public Author() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Author(String name, Book favoriteBook) {
|
||||||
|
this.name = name;
|
||||||
|
this.favoriteBook = favoriteBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Book getFavoriteBook() {
|
||||||
|
return favoriteBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFavoriteBook(Book favoriteBook) {
|
||||||
|
this.favoriteBook = favoriteBook;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,169 @@
|
||||||
|
package org.hibernate.orm.test.component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.annotations.Struct;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.util.ServiceRegistryUtil;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
@JiraKey( "HHH-15831" )
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructuralArrays.class)
|
||||||
|
public class StructNestedComponentAssociationErrorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOneToOneMappedByNested() {
|
||||||
|
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
||||||
|
try {
|
||||||
|
new MetadataSources( ssr )
|
||||||
|
.addAnnotatedClass( Book1.class )
|
||||||
|
.getMetadataBuilder()
|
||||||
|
.build();
|
||||||
|
Assertions.fail( "Expected a failure" );
|
||||||
|
}
|
||||||
|
catch (MappingException ex) {
|
||||||
|
assertThat( ex.getMessage(), containsString( "authorInfos.person.favoriteBook" ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
StandardServiceRegistryBuilder.destroy( ssr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book1 {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private AuthorInfo[] authorInfos;
|
||||||
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
|
private Book1 favoredBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct(name = "author_info_type")
|
||||||
|
public static class AuthorInfo {
|
||||||
|
Person1 person;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct(name = "person_type")
|
||||||
|
public static class Person1 {
|
||||||
|
private String name;
|
||||||
|
@OneToOne(mappedBy = "favoredBook", fetch = FetchType.LAZY)
|
||||||
|
private Book1 favoriteBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOneToManyMappedByNested() {
|
||||||
|
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
||||||
|
try {
|
||||||
|
new MetadataSources( ssr )
|
||||||
|
.addAnnotatedClass( Book2.class )
|
||||||
|
.getMetadataBuilder()
|
||||||
|
.build();
|
||||||
|
Assertions.fail( "Expected a failure" );
|
||||||
|
}
|
||||||
|
catch (MappingException ex) {
|
||||||
|
assertThat( ex.getMessage(), containsString( "authorInfos.person.bookCollection" ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
StandardServiceRegistryBuilder.destroy( ssr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book2 {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private AuthorInfo2[] authorInfos;
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private Book2 mainBook;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct(name = "author_info_type")
|
||||||
|
public static class AuthorInfo2 {
|
||||||
|
Person2 person;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct(name = "person_type")
|
||||||
|
public static class Person2 {
|
||||||
|
private String name;
|
||||||
|
@OneToMany(mappedBy = "mainBook")
|
||||||
|
private List<Book2> bookCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOneToMany() {
|
||||||
|
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
||||||
|
try {
|
||||||
|
new MetadataSources( ssr )
|
||||||
|
.addAnnotatedClass( Book3.class )
|
||||||
|
.getMetadataBuilder()
|
||||||
|
.build();
|
||||||
|
Assertions.fail( "Expected a failure" );
|
||||||
|
}
|
||||||
|
catch (MappingException ex) {
|
||||||
|
assertThat( ex.getMessage(), containsString( "authorInfos.person.bookCollection" ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
StandardServiceRegistryBuilder.destroy( ssr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Entity(name = "Book")
|
||||||
|
public static class Book3 {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private AuthorInfo3[] authorInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct(name = "author_info_type")
|
||||||
|
public static class AuthorInfo3 {
|
||||||
|
Person3 person;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Struct(name = "person_type")
|
||||||
|
public static class Person3 {
|
||||||
|
private String name;
|
||||||
|
@OneToMany
|
||||||
|
private List<Book3> bookCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue