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 )
|
||||
)
|
||||
);
|
||||
|
||||
jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1441,6 +1441,8 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
|||
.getDescriptor( Object.class )
|
||||
)
|
||||
);
|
||||
|
||||
jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,6 +47,16 @@ public @interface Struct {
|
|||
*/
|
||||
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.
|
||||
* 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( implicitColumnNamingSecondPassList );
|
||||
processSecondPasses( setBasicValueTypeSecondPassList );
|
||||
processSecondPasses( aggregateComponentSecondPassList );
|
||||
processSecondPasses( toOneJoinTableSecondPassList );
|
||||
|
||||
composites.forEach( Component::sortProperties );
|
||||
|
@ -1794,6 +1793,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
|||
|
||||
processPropertyReferences();
|
||||
|
||||
processSecondPasses( aggregateComponentSecondPassList );
|
||||
secondPassCompileForeignKeys( buildingContext );
|
||||
|
||||
processNaturalIdUniqueKeyBinders();
|
||||
|
|
|
@ -8,20 +8,20 @@ package org.hibernate.boot.model.internal;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.annotations.Struct;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
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.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.PropertyData;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.AggregateColumn;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.spi.EmbeddableAggregateJavaType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
@ -42,19 +42,18 @@ public final class AggregateComponentBinder {
|
|||
AnnotatedColumns columns,
|
||||
MetadataBuildingContext context) {
|
||||
if ( isAggregate( inferredData.getProperty(), componentXClass ) ) {
|
||||
validateComponent( component, BinderHelper.getPath( propertyHolder, inferredData ) );
|
||||
|
||||
final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
|
||||
final TypeConfiguration typeConfiguration = metadataCollector.getTypeConfiguration();
|
||||
// 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
|
||||
typeConfiguration.getJavaTypeRegistry().resolveDescriptor(
|
||||
component.getComponentClass(),
|
||||
() -> new EmbeddableAggregateJavaType<>( component.getComponentClass(), structName )
|
||||
);
|
||||
component.setStructName( structName );
|
||||
component.setStructName( structQualifiedName );
|
||||
component.setStructColumnNames( determineStructAttributeNames( inferredData, componentXClass ) );
|
||||
|
||||
// Determine the aggregate column
|
||||
|
@ -97,6 +96,7 @@ public final class AggregateComponentBinder {
|
|||
propertyHolder,
|
||||
component,
|
||||
componentXClass,
|
||||
inferredData.getPropertyName(),
|
||||
context
|
||||
)
|
||||
);
|
||||
|
@ -111,60 +111,59 @@ public final class AggregateComponentBinder {
|
|||
case SqlTypes.TABLE:
|
||||
return SqlTypes.STRUCT_TABLE;
|
||||
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) {
|
||||
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(
|
||||
private static QualifiedName determineStructName(
|
||||
AnnotatedColumns columns,
|
||||
PropertyData inferredData,
|
||||
XClass returnedClassOrElement) {
|
||||
XClass returnedClassOrElement,
|
||||
MetadataBuildingContext context) {
|
||||
final XProperty property = inferredData.getProperty();
|
||||
if ( property != null ) {
|
||||
final Struct struct = property.getAnnotation( Struct.class );
|
||||
if ( struct != null ) {
|
||||
return struct.name();
|
||||
return toQualifiedName( struct, context );
|
||||
}
|
||||
final JdbcTypeCode jdbcTypeCode = property.getAnnotation( JdbcTypeCode.class );
|
||||
if ( jdbcTypeCode != null
|
||||
&& ( jdbcTypeCode.value() == SqlTypes.STRUCT || jdbcTypeCode.value() == SqlTypes.STRUCT_ARRAY || jdbcTypeCode.value() == SqlTypes.STRUCT_TABLE )
|
||||
&& columns != null ) {
|
||||
final List<AnnotatedColumn> columnList = columns.getColumns();
|
||||
if ( columnList.size() == 1 && columnList.get( 0 ).getSqlType() != null ) {
|
||||
return columnList.get( 0 ).getSqlType();
|
||||
final String sqlType;
|
||||
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 );
|
||||
if ( struct != null ) {
|
||||
return struct.name();
|
||||
return toQualifiedName( struct, context );
|
||||
}
|
||||
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) {
|
||||
final XProperty property = inferredData.getProperty();
|
||||
if ( property != null ) {
|
||||
|
|
|
@ -11,25 +11,27 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.Comment;
|
||||
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.Namespace;
|
||||
import org.hibernate.boot.model.relational.QualifiedName;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.SecondPass;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.aggregate.AggregateSupport;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.AggregateColumn;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.UserDefinedObjectType;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.internal.EmbeddableHelper;
|
||||
|
@ -37,6 +39,8 @@ import org.hibernate.sql.Template;
|
|||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
|
@ -45,20 +49,26 @@ public class AggregateComponentSecondPass implements SecondPass {
|
|||
private final PropertyHolder propertyHolder;
|
||||
private final Component component;
|
||||
private final XClass componentXClass;
|
||||
private final String propertyName;
|
||||
private final MetadataBuildingContext context;
|
||||
|
||||
public AggregateComponentSecondPass(
|
||||
PropertyHolder propertyHolder,
|
||||
Component component,
|
||||
XClass componentXClass,
|
||||
String propertyName,
|
||||
MetadataBuildingContext context) {
|
||||
this.propertyHolder = propertyHolder;
|
||||
this.component = component;
|
||||
this.componentXClass = componentXClass;
|
||||
this.propertyName = propertyName;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||
validateComponent( component, qualify( propertyHolder.getPath(), propertyName ), isAggregateArray() );
|
||||
|
||||
final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
|
||||
final TypeConfiguration typeConfiguration = metadataCollector.getTypeConfiguration();
|
||||
final Database database = metadataCollector.getDatabase();
|
||||
|
@ -72,21 +82,17 @@ public class AggregateComponentSecondPass implements SecondPass {
|
|||
final List<Column> aggregatedColumns = component.getAggregatedColumns();
|
||||
final AggregateColumn aggregateColumn = component.getAggregateColumn();
|
||||
|
||||
ensureInitialized( metadataCollector, typeConfiguration, dialect, aggregateColumn );
|
||||
ensureInitialized( metadataCollector, aggregateColumn );
|
||||
validateSupportedColumnTypes( propertyHolder.getPath(), component );
|
||||
|
||||
for ( org.hibernate.mapping.Column aggregatedColumn : aggregatedColumns ) {
|
||||
// Make sure this state is initialized
|
||||
aggregatedColumn.getSqlTypeCode( metadataCollector );
|
||||
aggregatedColumn.getSqlType( metadataCollector );
|
||||
}
|
||||
|
||||
final String structName = component.getStructName();
|
||||
final QualifiedName structName = component.getStructName();
|
||||
final boolean addAuxiliaryObjects;
|
||||
if ( structName != null ) {
|
||||
final Namespace defaultNamespace = database.getDefaultNamespace();
|
||||
final Identifier udtName = Identifier.toIdentifier( structName );
|
||||
final UserDefinedObjectType udt = new UserDefinedObjectType( "orm", defaultNamespace, udtName );
|
||||
final Namespace namespace = database.locateNamespace(
|
||||
structName.getCatalogName(),
|
||||
structName.getSchemaName()
|
||||
);
|
||||
final UserDefinedObjectType udt = new UserDefinedObjectType( "orm", namespace, structName.getObjectName() );
|
||||
final Comment comment = componentXClass.getAnnotation( Comment.class );
|
||||
if ( comment != null ) {
|
||||
udt.setComment( comment.value() );
|
||||
|
@ -94,8 +100,8 @@ public class AggregateComponentSecondPass implements SecondPass {
|
|||
for ( org.hibernate.mapping.Column aggregatedColumn : aggregatedColumns ) {
|
||||
udt.addColumn( aggregatedColumn );
|
||||
}
|
||||
final UserDefinedObjectType registeredUdt = defaultNamespace.createUserDefinedType(
|
||||
udtName,
|
||||
final UserDefinedObjectType registeredUdt = namespace.createUserDefinedType(
|
||||
structName.getObjectName(),
|
||||
name -> udt
|
||||
);
|
||||
if ( registeredUdt == udt ) {
|
||||
|
@ -187,6 +193,66 @@ public class AggregateComponentSecondPass implements SecondPass {
|
|||
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) {
|
||||
final Class<?> componentClass = component.getComponentClass();
|
||||
final String[] structColumnNames = component.getStructColumnNames();
|
||||
|
@ -303,7 +369,7 @@ public class AggregateComponentSecondPass implements SecondPass {
|
|||
if ( value instanceof Component ) {
|
||||
final Component subComponent = (Component) value;
|
||||
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(
|
||||
InFlightMetadataCollector metadataCollector,
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect,
|
||||
AggregateColumn aggregateColumn) {
|
||||
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) {
|
||||
do {
|
||||
// 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 );
|
||||
|
||||
if ( columns.getPropertyHolder().isComponent() ) {
|
||||
final ComponentPropertyHolder propertyHolder = (ComponentPropertyHolder) columns.getPropertyHolder();
|
||||
basicValue.setAggregateColumn( propertyHolder.getAggregateColumn() );
|
||||
}
|
||||
|
||||
if ( isNationalized() ) {
|
||||
basicValue.makeNationalized();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hibernate.annotations.common.reflection.XClass;
|
|||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.PropertyData;
|
||||
import org.hibernate.mapping.AggregateColumn;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.Join;
|
||||
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 ( columns != null ) {
|
||||
final Table table = columns.getTable();
|
||||
if ( !table.equals( component.getTable() ) ) {
|
||||
if ( !table.equals( getTable() ) ) {
|
||||
if ( component.getPropertySpan() == 0 ) {
|
||||
component.setTable( table );
|
||||
}
|
||||
|
@ -301,6 +302,11 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
|
|||
return component.getOwner().getClassName();
|
||||
}
|
||||
|
||||
public AggregateColumn getAggregateColumn() {
|
||||
final AggregateColumn aggregateColumn = component.getAggregateColumn();
|
||||
return aggregateColumn != null ? aggregateColumn : component.getParentAggregateColumn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table 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.PropertyData;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.mapping.AggregateColumn;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.Property;
|
||||
|
@ -371,6 +372,14 @@ public class EmbeddableBinder {
|
|||
returnedClassOrElement = context.getBootstrapContext().getReflectionManager()
|
||||
.toXClass( compositeUserType.embeddable() );
|
||||
}
|
||||
AggregateComponentBinder.processAggregate(
|
||||
component,
|
||||
propertyHolder,
|
||||
inferredData,
|
||||
returnedClassOrElement,
|
||||
columns,
|
||||
context
|
||||
);
|
||||
|
||||
final XClass annotatedClass = inferredData.getPropertyClass();
|
||||
final List<PropertyData> classElements =
|
||||
|
@ -447,14 +456,6 @@ public class EmbeddableBinder {
|
|||
processCompositeUserType( component, compositeUserType );
|
||||
}
|
||||
|
||||
AggregateComponentBinder.processAggregate(
|
||||
component,
|
||||
propertyHolder,
|
||||
inferredData,
|
||||
returnedClassOrElement,
|
||||
columns,
|
||||
context
|
||||
);
|
||||
return component;
|
||||
}
|
||||
|
||||
|
@ -563,6 +564,7 @@ public class EmbeddableBinder {
|
|||
columns.setBuildingContext( context );
|
||||
discriminatorColumn.setParent( columns );
|
||||
final BasicValue discriminatorColumnBinding = new BasicValue( context, component.getTable() );
|
||||
discriminatorColumnBinding.setAggregateColumn( component.getAggregateColumn() );
|
||||
component.setDiscriminator( discriminatorColumnBinding );
|
||||
discriminatorColumn.linkWithValue( discriminatorColumnBinding );
|
||||
discriminatorColumnBinding.setTypeName( discriminatorColumn.getDiscriminatorTypeName() );
|
||||
|
@ -858,6 +860,10 @@ public class EmbeddableBinder {
|
|||
if ( constructor != null ) {
|
||||
component.setInstantiator( constructor, constructor.getAnnotation( Instantiator.class ).value() );
|
||||
}
|
||||
if ( propertyHolder.isComponent() ) {
|
||||
final ComponentPropertyHolder componentPropertyHolder = (ComponentPropertyHolder) propertyHolder;
|
||||
component.setParentAggregateColumn( componentPropertyHolder.getAggregateColumn() );
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.hibernate.mapping.UserDefinedArrayType;
|
|||
import org.hibernate.mapping.UserDefinedObjectType;
|
||||
import org.hibernate.mapping.UserDefinedType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SqlTypedJdbcType;
|
||||
|
@ -183,7 +184,9 @@ public class Namespace {
|
|||
final UserDefinedType udt = entry.getValue();
|
||||
if ( udt instanceof UserDefinedObjectType ) {
|
||||
for ( Column udtColumn : ( (UserDefinedObjectType) udt ).getColumns() ) {
|
||||
final JdbcType jdbcType = ( (BasicType<?>) udtColumn.getValue().getType() ).getJdbcType();
|
||||
final Type udtColumnType = udtColumn.getValue().getType();
|
||||
if ( udtColumnType instanceof BasicType<?> ) {
|
||||
final JdbcType jdbcType = ( (BasicType<?>) udtColumnType ).getJdbcType();
|
||||
if ( jdbcType instanceof SqlTypedJdbcType ) {
|
||||
dependencies.add( Identifier.toIdentifier( ( (SqlTypedJdbcType) jdbcType ).getSqlTypeName() ) );
|
||||
}
|
||||
|
@ -194,6 +197,7 @@ public class Namespace {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( dependencies.isEmpty() ) {
|
||||
// The UDTs without dependencies are added directly
|
||||
orderedUdts.put( udt.getNameIdentifier(), udt );
|
||||
|
|
|
@ -24,13 +24,11 @@ import java.util.ArrayList;
|
|||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.internal.util.CharSequenceHelper;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
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.StringBuilderSqlAppender;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
|
@ -1008,7 +1006,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
|||
final int size = numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
|
||||
int count = 0;
|
||||
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();
|
||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
||||
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
|
||||
|
@ -1178,7 +1176,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
|||
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 ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1187,86 +1185,62 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
private void serializeStructTo(PostgreSQLAppender appender, Object value, WrapperOptions options) {
|
||||
serializeValuesTo( appender, options, embeddableMappingType, value, '(' );
|
||||
private void serializeStructTo(PostgreSQLAppender appender, Object value, WrapperOptions options) throws SQLException {
|
||||
serializeDomainValueTo( appender, options, value, '(' );
|
||||
appender.append( ')' );
|
||||
}
|
||||
|
||||
private void serializeValuesTo(
|
||||
private void serializeDomainValueTo(
|
||||
PostgreSQLAppender appender,
|
||||
WrapperOptions options,
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
Object domainValue,
|
||||
char separator) {
|
||||
final Object[] array = embeddableMappingType.getValues( domainValue );
|
||||
final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
|
||||
for ( int i = 0; i < array.length; i++ ) {
|
||||
final ValuedModelPart attributeMapping;
|
||||
final Object attributeValue;
|
||||
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(
|
||||
char separator) throws SQLException {
|
||||
serializeJdbcValuesTo(
|
||||
appender,
|
||||
options,
|
||||
mappingType,
|
||||
attributeValue,
|
||||
StructHelper.getJdbcValues( embeddableMappingType, orderMapping, domainValue, options ),
|
||||
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,
|
||||
WrapperOptions options,
|
||||
JdbcMapping jdbcMapping,
|
||||
Object value) {
|
||||
serializeConvertedBasicTo( appender, options, jdbcMapping, jdbcMapping.convertToRelationalValue( value ) );
|
||||
Object[] jdbcValues,
|
||||
char separator) throws SQLException {
|
||||
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(
|
||||
PostgreSQLAppender appender,
|
||||
WrapperOptions options,
|
||||
JdbcMapping jdbcMapping,
|
||||
Object subValue) {
|
||||
Object subValue) throws SQLException {
|
||||
//noinspection unchecked
|
||||
final JavaType<Object> jdbcJavaType = (JavaType<Object>) jdbcMapping.getJdbcJavaType();
|
||||
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
|
||||
|
@ -1291,14 +1265,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
|||
case SqlTypes.DECIMAL:
|
||||
case SqlTypes.NUMERIC:
|
||||
case SqlTypes.DURATION:
|
||||
jdbcJavaType.appendEncodedString(
|
||||
appender,
|
||||
jdbcJavaType.unwrap(
|
||||
subValue,
|
||||
jdbcJavaType.getJavaTypeClass(),
|
||||
options
|
||||
)
|
||||
);
|
||||
appender.append( subValue.toString() );
|
||||
break;
|
||||
case SqlTypes.CHAR:
|
||||
case SqlTypes.NCHAR:
|
||||
|
@ -1316,14 +1283,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
|||
case SqlTypes.ENUM:
|
||||
case SqlTypes.NAMED_ENUM:
|
||||
appender.quoteStart();
|
||||
jdbcJavaType.appendEncodedString(
|
||||
appender,
|
||||
jdbcJavaType.unwrap(
|
||||
subValue,
|
||||
jdbcJavaType.getJavaTypeClass(),
|
||||
options
|
||||
)
|
||||
);
|
||||
appender.append( (String) subValue );
|
||||
appender.quoteEnd();
|
||||
break;
|
||||
case SqlTypes.DATE:
|
||||
|
@ -1393,9 +1353,8 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
|||
case SqlTypes.STRUCT:
|
||||
if ( subValue != null ) {
|
||||
final AbstractPostgreSQLStructJdbcType structJdbcType = (AbstractPostgreSQLStructJdbcType) jdbcMapping.getJdbcType();
|
||||
final EmbeddableMappingType subEmbeddableMappingType = structJdbcType.getEmbeddableMappingType();
|
||||
appender.quoteStart();
|
||||
structJdbcType.serializeValuesTo( appender, options, subEmbeddableMappingType, subValue, '(' );
|
||||
structJdbcType.serializeJdbcValuesTo( appender, options, (Object[]) subValue, '(' );
|
||||
appender.append( ')' );
|
||||
appender.quoteEnd();
|
||||
}
|
||||
|
@ -1427,9 +1386,8 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
|||
else {
|
||||
attributeIndex = orderMapping[i];
|
||||
}
|
||||
final ValuedModelPart modelPart = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, attributeIndex );
|
||||
jdbcIndex += injectAttributeValue(
|
||||
modelPart,
|
||||
getEmbeddedPart( embeddableMappingType, attributeIndex ),
|
||||
attributeValues,
|
||||
attributeIndex,
|
||||
rawJdbcValues,
|
||||
|
@ -1567,6 +1525,10 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
|
|||
: 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 int quote = 1;
|
||||
|
|
|
@ -410,6 +410,8 @@ public class CockroachDialect extends Dialect {
|
|||
.getDescriptor( Object.class )
|
||||
)
|
||||
);
|
||||
|
||||
jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -73,7 +73,7 @@ public class JsonHelper {
|
|||
final Object[] values = embeddableMappingType.getValues( domainValue );
|
||||
final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
|
||||
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 ) {
|
||||
final String name = ( (SelectableMapping) attributeMapping ).getSelectableName();
|
||||
appender.append( separator );
|
||||
|
|
|
@ -69,6 +69,8 @@ public class OracleArrayJdbcType extends ArrayJdbcType implements SqlTypedJdbcTy
|
|||
|
||||
@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 ) {
|
||||
private String typeName(WrapperOptions options) {
|
||||
return ( upperTypeName == null
|
||||
|
@ -105,7 +107,7 @@ public class OracleArrayJdbcType extends ArrayJdbcType implements SqlTypedJdbcTy
|
|||
|
||||
@Override
|
||||
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 OracleConnection oracleConnection = options.getSession()
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Locale;
|
||||
|
||||
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.SelectableMapping;
|
||||
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.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||
|
||||
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
|
||||
public String getExtraCreateTableInfo(
|
||||
JavaType<?> javaType,
|
||||
|
@ -51,7 +79,9 @@ public class OracleBaseStructJdbcType extends StructJdbcType {
|
|||
.locateUserDefinedType( Identifier.toIdentifier( getSqlTypeName() ) );
|
||||
StringBuilder sb = null;
|
||||
for ( Column column : udt.getColumns() ) {
|
||||
final JdbcMapping jdbcMapping = (JdbcMapping) column.getValue().getType();
|
||||
final Type columnType = column.getValue().getType();
|
||||
if ( columnType instanceof JdbcMapping ) {
|
||||
final JdbcMapping jdbcMapping = (JdbcMapping) columnType;
|
||||
final String extraCreateTableInfo = jdbcMapping.getJdbcType().getExtraCreateTableInfo(
|
||||
jdbcMapping.getJavaTypeDescriptor(),
|
||||
columnName + "." + column.getName(),
|
||||
|
@ -68,6 +98,7 @@ public class OracleBaseStructJdbcType extends StructJdbcType {
|
|||
sb.append( extraCreateTableInfo );
|
||||
}
|
||||
}
|
||||
}
|
||||
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( PostgreSQLOrdinalEnumJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptor( PostgreSQLUUIDJdbcType.INSTANCE );
|
||||
|
||||
jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -89,6 +89,11 @@ public class PostgreSQLStructCastingJdbcType extends AbstractPostgreSQLStructJdb
|
|||
);
|
||||
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 );
|
||||
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.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
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.MappingType;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
@ -39,12 +45,14 @@ public class StructHelper {
|
|||
final StructAttributeValues attributeValues = new StructAttributeValues( numberOfAttributeMappings, rawJdbcValues );
|
||||
int jdbcIndex = 0;
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final ValuedModelPart valuedModelPart = getEmbeddedPart(
|
||||
embeddableMappingType,
|
||||
numberOfAttributeMappings,
|
||||
i
|
||||
jdbcIndex += injectAttributeValue(
|
||||
getEmbeddedPart( embeddableMappingType, i ),
|
||||
attributeValues,
|
||||
i,
|
||||
rawJdbcValues,
|
||||
jdbcIndex,
|
||||
options
|
||||
);
|
||||
jdbcIndex += injectAttributeValue( valuedModelPart, attributeValues, i, rawJdbcValues, jdbcIndex, options );
|
||||
}
|
||||
return attributeValues;
|
||||
}
|
||||
|
@ -104,26 +112,58 @@ public class StructHelper {
|
|||
else {
|
||||
jdbcValues = values;
|
||||
}
|
||||
int jdbcIndex = 0;
|
||||
for ( int i = 0; i < values.length; i++ ) {
|
||||
final int attributeIndex;
|
||||
if ( orderMapping == null ) {
|
||||
attributeIndex = i;
|
||||
}
|
||||
else {
|
||||
attributeIndex = orderMapping[i];
|
||||
}
|
||||
jdbcIndex += injectJdbcValue(
|
||||
getEmbeddedPart( embeddableMappingType, jdbcValueCount, attributeIndex ),
|
||||
injectJdbcValues(
|
||||
embeddableMappingType,
|
||||
values,
|
||||
attributeIndex,
|
||||
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
|
||||
);
|
||||
}
|
||||
assert jdbcIndex == valueCount;
|
||||
return jdbcValues;
|
||||
|
||||
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++ ) {
|
||||
offset += injectJdbcValue(
|
||||
getEmbeddedPart( embeddableMappingType, i ),
|
||||
values,
|
||||
i,
|
||||
jdbcValues,
|
||||
jdbcIndex + offset,
|
||||
options
|
||||
);
|
||||
}
|
||||
assert offset == valueCount;
|
||||
return offset;
|
||||
}
|
||||
|
||||
public static Object instantiate(
|
||||
|
@ -142,13 +182,10 @@ public class StructHelper {
|
|||
return instantiator.instantiate( attributeValues, sessionFactory );
|
||||
}
|
||||
|
||||
public static ValuedModelPart getEmbeddedPart(
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
int numberOfAttributes,
|
||||
int position) {
|
||||
return position == numberOfAttributes ?
|
||||
embeddableMappingType.getDiscriminatorMapping() :
|
||||
embeddableMappingType.getAttributeMapping( position );
|
||||
public static ValuedModelPart getEmbeddedPart(EmbeddableMappingType embeddableMappingType, int position) {
|
||||
return position == embeddableMappingType.getNumberOfAttributeMappings()
|
||||
? embeddableMappingType.getDiscriminatorMapping()
|
||||
: embeddableMappingType.getAttributeMapping( position );
|
||||
}
|
||||
|
||||
private static int injectJdbcValue(
|
||||
|
@ -158,16 +195,61 @@ public class StructHelper {
|
|||
Object[] jdbcValues,
|
||||
int jdbcIndex,
|
||||
WrapperOptions options) throws SQLException {
|
||||
final MappingType mappedType = attributeMapping.getMappedType();
|
||||
final int jdbcValueCount;
|
||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
||||
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
|
||||
if ( embeddableMappingType.getAggregateMapping() != null ) {
|
||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableMappingType.getAggregateMapping()
|
||||
.getJdbcMapping()
|
||||
.getJdbcType();
|
||||
if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping;
|
||||
if ( toOneAttributeMapping.getSideNature() == ForeignKeyDescriptor.Nature.TARGET ) {
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
jdbcValues[jdbcIndex] = aggregateJdbcType.createJdbcValue(
|
||||
jdbcValues[jdbcIndex] = foreignKeyValue;
|
||||
}
|
||||
else if ( keyPart instanceof EmbeddableValuedModelPart ) {
|
||||
final EmbeddableMappingType mappingType = ( (EmbeddableValuedModelPart) keyPart ).getEmbeddableTypeDescriptor();
|
||||
jdbcValueCount = injectJdbcValues(
|
||||
mappingType,
|
||||
foreignKeyValue,
|
||||
jdbcValues,
|
||||
jdbcIndex,
|
||||
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
|
||||
);
|
||||
|
@ -180,7 +262,7 @@ public class StructHelper {
|
|||
int offset = 0;
|
||||
for ( int i = 0; i < numberOfValues; i++ ) {
|
||||
offset += injectJdbcValue(
|
||||
getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, i ),
|
||||
getEmbeddedPart( embeddableMappingType, i ),
|
||||
subValues,
|
||||
i,
|
||||
jdbcValues,
|
||||
|
@ -251,23 +333,27 @@ public class StructHelper {
|
|||
int[] inverseMapping,
|
||||
Object[] sourceJdbcValues,
|
||||
Object[] targetJdbcValues) {
|
||||
final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
|
||||
int targetJdbcOffset = 0;
|
||||
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 i = 0; i < inverseMapping.length; i++ ) {
|
||||
targetJdbcValues[i] = sourceJdbcValues[inverseMapping[i]];
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -13,10 +13,16 @@ import java.sql.SQLException;
|
|||
import java.sql.Struct;
|
||||
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
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.MappingType;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
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.type.BasicPluralType;
|
||||
import org.hibernate.type.BasicType;
|
||||
|
@ -144,9 +150,12 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
|||
|
||||
@Override
|
||||
public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException {
|
||||
final Object[] attributes = ( (Struct) rawJdbcValue ).getAttributes();
|
||||
wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, attributes, 0, options );
|
||||
return attributes;
|
||||
final Object[] jdbcValues = ( (Struct) rawJdbcValue ).getAttributes();
|
||||
if ( orderMapping != null ) {
|
||||
StructHelper.orderJdbcValues( embeddableMappingType, inverseOrderMapping, jdbcValues.clone(), jdbcValues );
|
||||
}
|
||||
wrapRawJdbcValues( embeddableMappingType, jdbcValues, 0, options );
|
||||
return jdbcValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -198,18 +207,21 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
|||
return null;
|
||||
}
|
||||
final Struct struct = (Struct) object;
|
||||
final Object[] values = struct.getAttributes();
|
||||
final Object[] jdbcValues = struct.getAttributes();
|
||||
final boolean jdbcRepresentation = getJavaType().getJavaTypeClass() == Object[].class;
|
||||
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
|
||||
return (X) values;
|
||||
return (X) jdbcValues;
|
||||
}
|
||||
assert embeddableMappingType != null && embeddableMappingType.getJavaType() == getJavaType();
|
||||
final StructAttributeValues attributeValues = getAttributeValues(
|
||||
embeddableMappingType,
|
||||
orderMapping,
|
||||
values,
|
||||
jdbcValues,
|
||||
options
|
||||
);
|
||||
//noinspection unchecked
|
||||
|
@ -240,9 +252,8 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
|||
else {
|
||||
attributeIndex = orderMapping[i];
|
||||
}
|
||||
final ValuedModelPart modelPart = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, attributeIndex );
|
||||
jdbcIndex += injectAttributeValue(
|
||||
modelPart,
|
||||
getEmbeddedPart( embeddableMappingType, attributeIndex ),
|
||||
attributeValues,
|
||||
attributeIndex,
|
||||
rawJdbcValues,
|
||||
|
@ -381,55 +392,96 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
|||
|
||||
private int wrapRawJdbcValues(
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
int[] orderMapping,
|
||||
int[] inverseOrderMapping,
|
||||
Object[] jdbcValues,
|
||||
int jdbcIndex,
|
||||
WrapperOptions options) throws SQLException {
|
||||
final Object[] targetJdbcValues;
|
||||
if ( orderMapping == null ) {
|
||||
targetJdbcValues = jdbcValues;
|
||||
}
|
||||
else {
|
||||
targetJdbcValues = jdbcValues.clone();
|
||||
}
|
||||
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
|
||||
for ( int i = 0; i < numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 ); i++ ) {
|
||||
final ValuedModelPart attributeMapping;
|
||||
if ( orderMapping == null ) {
|
||||
attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, i );
|
||||
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, i );
|
||||
if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||
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 {
|
||||
attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, orderMapping[i] );
|
||||
throw new UnsupportedOperationException( "Unsupported foreign key part: " + keyPart );
|
||||
}
|
||||
final MappingType mappedType = attributeMapping.getMappedType();
|
||||
|
||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
||||
final EmbeddableMappingType embeddableType = (EmbeddableMappingType) mappedType;
|
||||
}
|
||||
else if ( attributeMapping instanceof PluralAttributeMapping ) {
|
||||
continue;
|
||||
}
|
||||
else if ( attributeMapping instanceof DiscriminatedAssociationAttributeMapping ) {
|
||||
final DiscriminatedAssociationAttributeMapping discriminatedAssociationAttributeMapping = (DiscriminatedAssociationAttributeMapping) attributeMapping;
|
||||
wrapRawJdbcValue(
|
||||
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 ) {
|
||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableType.getAggregateMapping()
|
||||
.getJdbcMapping()
|
||||
.getJdbcType();
|
||||
final Object rawJdbcValue = targetJdbcValues[jdbcIndex];
|
||||
targetJdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
|
||||
final Object rawJdbcValue = jdbcValues[jdbcIndex];
|
||||
jdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
|
||||
jdbcIndex++;
|
||||
}
|
||||
else {
|
||||
jdbcIndex = wrapRawJdbcValues( embeddableType, null, null, targetJdbcValues, jdbcIndex, options );
|
||||
jdbcIndex = wrapRawJdbcValues( embeddableType, jdbcValues, jdbcIndex, options );
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert attributeMapping.getJdbcTypeCount() == 1;
|
||||
final Object rawJdbcValue = targetJdbcValues[jdbcIndex];
|
||||
if ( rawJdbcValue != null ) {
|
||||
final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping();
|
||||
wrapRawJdbcValue( attributeMapping.getSingleJdbcMapping(), jdbcValues, jdbcIndex, options );
|
||||
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
|
||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType()
|
||||
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType()
|
||||
.wrap( transformRawJdbcValue( rawJdbcValue, options ), options );
|
||||
break;
|
||||
case SqlTypes.ARRAY:
|
||||
|
@ -451,7 +503,7 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
|||
options
|
||||
);
|
||||
}
|
||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( newArray, options );
|
||||
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( newArray, options );
|
||||
break;
|
||||
case SqlTypes.STRUCT:
|
||||
case SqlTypes.JSON:
|
||||
|
@ -471,26 +523,18 @@ public class StructJdbcType implements org.hibernate.type.descriptor.jdbc.Struct
|
|||
);
|
||||
newArray[j] = instantiate( subEmbeddableMappingType, subValues, options.getSessionFactory() );
|
||||
}
|
||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( newArray, options );
|
||||
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( newArray, options );
|
||||
break;
|
||||
default:
|
||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||
jdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||
break;
|
||||
}
|
||||
}
|
||||
jdbcIndex++;
|
||||
}
|
||||
}
|
||||
if ( orderMapping != null ) {
|
||||
StructHelper.orderJdbcValues( embeddableMappingType, inverseOrderMapping, targetJdbcValues, jdbcValues );
|
||||
}
|
||||
return jdbcIndex;
|
||||
}
|
||||
|
||||
protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) {
|
||||
return rawJdbcValue;
|
||||
|
|
|
@ -493,7 +493,7 @@ public class XmlHelper {
|
|||
if ( array[i] == null ) {
|
||||
continue;
|
||||
}
|
||||
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributes, i );
|
||||
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, i );
|
||||
if ( attributeMapping instanceof SelectableMapping ) {
|
||||
final SelectableMapping selectable = (SelectableMapping) attributeMapping;
|
||||
final String tagName = selectable.getSelectableName();
|
||||
|
|
|
@ -94,7 +94,10 @@ public class GeneratedValueBasicResultBuilder implements ResultBuilder {
|
|||
return new BasicResult<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
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.STRUCT_ARRAY;
|
||||
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},
|
||||
|
@ -79,7 +80,9 @@ public class AggregateColumn extends Column {
|
|||
final AggregateColumn parentAggregateColumn = component.getParentAggregateColumn();
|
||||
final String simpleAggregateName = aggregateColumn.getQuotedName( dialect );
|
||||
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 );
|
||||
}
|
||||
else {
|
||||
|
@ -99,13 +102,23 @@ public class AggregateColumn extends Column {
|
|||
}
|
||||
|
||||
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() ) {
|
||||
case JSON_ARRAY:
|
||||
case XML_ARRAY:
|
||||
case STRUCT_ARRAY:
|
||||
case STRUCT_TABLE:
|
||||
return Template.TEMPLATE;
|
||||
return true;
|
||||
default:
|
||||
return Template.TEMPLATE + "." + simpleAggregateName;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -967,7 +967,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
return aggregateColumn == null
|
||||
? jdbcTypeCode
|
||||
: getDialect().getAggregateSupport()
|
||||
.aggregateComponentSqlTypeCode( aggregateColumn.getSqlTypeCode(), jdbcTypeCode );
|
||||
.aggregateComponentSqlTypeCode( aggregateColumn.getSqlTypeCode( getMetadata() ), jdbcTypeCode );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.Remove;
|
|||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
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.source.internal.hbm.MappingDocument;
|
||||
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 parentAggregateColumn;
|
||||
private String structName;
|
||||
private QualifiedName structName;
|
||||
private String[] structColumnNames;
|
||||
private transient Class<?> componentClass;
|
||||
// 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;
|
||||
}
|
||||
|
||||
public String getStructName() {
|
||||
public QualifiedName getStructName() {
|
||||
return structName;
|
||||
}
|
||||
|
||||
public void setStructName(String structName) {
|
||||
public void setStructName(QualifiedName structName) {
|
||||
this.structName = structName;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,8 @@ public interface CollectionPart extends ValuedModelPart, Fetchable, JavaTypedExp
|
|||
|
||||
Nature getNature();
|
||||
|
||||
PluralAttributeMapping getCollectionAttribute();
|
||||
|
||||
@Override
|
||||
default String getPartName() {
|
||||
return getNature().getName();
|
||||
|
|
|
@ -12,9 +12,11 @@ import java.util.function.BiConsumer;
|
|||
|
||||
import org.hibernate.internal.util.IndexedConsumer;
|
||||
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.MappingModelCreationProcess;
|
||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
||||
import org.hibernate.property.access.spi.Getter;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
@ -156,9 +158,43 @@ public interface EmbeddableMappingType extends ManagedMappingType, SelectableMap
|
|||
int count = 0;
|
||||
for ( int i = 0; i < numberOfAttributeMappings; i++ ) {
|
||||
final AttributeMapping attributeMapping = getAttributeMapping( i );
|
||||
final MappingType mappedType = attributeMapping.getMappedType();
|
||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
||||
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
|
||||
if ( attributeMapping instanceof DiscriminatedAssociationAttributeMapping ) {
|
||||
final DiscriminatedAssociationAttributeMapping discriminatedAssociationAttributeMapping = (DiscriminatedAssociationAttributeMapping) attributeMapping;
|
||||
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();
|
||||
if ( aggregateMapping == null ) {
|
||||
final SelectableMapping subSelectable = embeddableMappingType.getJdbcValueSelectable( columnIndex - count );
|
||||
|
@ -176,8 +212,11 @@ public interface EmbeddableMappingType extends ManagedMappingType, SelectableMap
|
|||
}
|
||||
else {
|
||||
if ( count == columnIndex ) {
|
||||
if ( attributeMapping instanceof SelectableMapping ) {
|
||||
return (SelectableMapping) attributeMapping;
|
||||
}
|
||||
assert attributeMapping.getJdbcTypeCount() == 0;
|
||||
}
|
||||
count += attributeMapping.getJdbcTypeCount();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ public interface PluralAttributeMapping
|
|||
TableGroup parentTableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new BasicResult( 0, null, getJavaType() );
|
||||
return new BasicResult( 0, null, getJavaType(), null, null, false, false );
|
||||
}
|
||||
|
||||
String getSeparateCollectionTable();
|
||||
|
|
|
@ -13,7 +13,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|||
import org.hibernate.internal.util.IndexedConsumer;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorConverter;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorType;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorValueDetails;
|
||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
|
@ -124,7 +123,9 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
|
|||
resultVariable,
|
||||
discriminatorType.getJavaTypeDescriptor(),
|
||||
discriminatorType.getValueConverter(),
|
||||
navigablePath
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -175,7 +176,10 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
|
|||
this,
|
||||
discriminatorType.getValueConverter(),
|
||||
fetchTiming,
|
||||
creationState
|
||||
true,
|
||||
creationState,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,11 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
|
|||
return nature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluralAttributeMapping getCollectionAttribute() {
|
||||
return collectionDescriptor.getAttributeMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFetchableName() {
|
||||
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.results.graph.DomainResult;
|
||||
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.FetchParent;
|
||||
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 column;
|
||||
private final String customReadExpression;
|
||||
private final String customWriteExpression;
|
||||
private final String columnDefinition;
|
||||
private final Long length;
|
||||
private final Integer precision;
|
||||
|
@ -75,7 +76,7 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
|||
NavigableRole partRole,
|
||||
DiscriminatedAssociationModelPart declaringType,
|
||||
String table,
|
||||
String column,
|
||||
String column, String customReadExpression, String customWriteExpression,
|
||||
String columnDefinition,
|
||||
Long length,
|
||||
Integer precision,
|
||||
|
@ -90,6 +91,8 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
|||
this.declaringType = declaringType;
|
||||
this.table = table;
|
||||
this.column = column;
|
||||
this.customReadExpression = customReadExpression;
|
||||
this.customWriteExpression = customWriteExpression;
|
||||
this.columnDefinition = columnDefinition;
|
||||
this.length = length;
|
||||
this.precision = precision;
|
||||
|
@ -160,12 +163,12 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
|||
|
||||
@Override
|
||||
public String getCustomReadExpression() {
|
||||
return null;
|
||||
return customReadExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCustomWriteExpression() {
|
||||
return null;
|
||||
return customWriteExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -326,7 +329,8 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
|||
fetchablePath,
|
||||
this,
|
||||
fetchTiming,
|
||||
creationState
|
||||
creationState,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -351,7 +355,9 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
jdbcMapping(),
|
||||
navigablePath
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
private final String table;
|
||||
private final String column;
|
||||
private final DiscriminatedAssociationModelPart anyPart;
|
||||
private final String customReadExpression;
|
||||
private final String customWriteExpression;
|
||||
private final String columnDefinition;
|
||||
private final Long length;
|
||||
private final Integer precision;
|
||||
|
@ -63,6 +65,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
DiscriminatedAssociationModelPart anyPart,
|
||||
String table,
|
||||
String column,
|
||||
String customReadExpression,
|
||||
String customWriteExpression,
|
||||
String columnDefinition,
|
||||
Long length,
|
||||
Integer precision,
|
||||
|
@ -76,6 +80,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
this.table = table;
|
||||
this.column = column;
|
||||
this.anyPart = anyPart;
|
||||
this.customReadExpression = customReadExpression;
|
||||
this.customWriteExpression = customWriteExpression;
|
||||
this.columnDefinition = columnDefinition;
|
||||
this.length = length;
|
||||
this.precision = precision;
|
||||
|
@ -124,12 +130,12 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
|
||||
@Override
|
||||
public String getCustomReadExpression() {
|
||||
return null;
|
||||
return customReadExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCustomWriteExpression() {
|
||||
return null;
|
||||
return customWriteExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -242,7 +248,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
fetchablePath,
|
||||
this,
|
||||
fetchTiming,
|
||||
creationState
|
||||
creationState,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -333,7 +340,9 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
jdbcMapping,
|
||||
navigablePath
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -337,7 +337,9 @@ public class BasicAttributeMapping
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
jdbcMapping,
|
||||
navigablePath
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -391,10 +393,12 @@ public class BasicAttributeMapping
|
|||
DomainResultCreationState creationState) {
|
||||
final int valuesArrayPosition;
|
||||
boolean coerceResultType = false;
|
||||
final SqlSelection sqlSelection;
|
||||
if ( fetchTiming == FetchTiming.DELAYED && isLazy ) {
|
||||
// Lazy property. A valuesArrayPosition of -1 will lead to
|
||||
// returning a domain result assembler that returns LazyPropertyInitializer.UNFETCHED_PROPERTY
|
||||
valuesArrayPosition = -1;
|
||||
sqlSelection = null;
|
||||
}
|
||||
else {
|
||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||
|
@ -404,7 +408,7 @@ public class BasicAttributeMapping
|
|||
|
||||
assert tableGroup != null;
|
||||
|
||||
final SqlSelection sqlSelection = resolveSqlSelection(
|
||||
sqlSelection = resolveSqlSelection(
|
||||
fetchablePath,
|
||||
tableGroup,
|
||||
fetchParent,
|
||||
|
@ -422,9 +426,12 @@ public class BasicAttributeMapping
|
|||
fetchParent,
|
||||
fetchablePath,
|
||||
this,
|
||||
getJdbcMapping().getValueConverter(),
|
||||
fetchTiming,
|
||||
true,
|
||||
creationState,
|
||||
coerceResultType
|
||||
coerceResultType,
|
||||
sqlSelection != null && !sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -231,7 +231,9 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
entityPersister.getIdentifierMapping().getSingleJdbcMapping(),
|
||||
navigablePath
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -425,10 +427,13 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
fetchParent,
|
||||
fetchablePath,
|
||||
this,
|
||||
getJdbcMapping().getValueConverter(),
|
||||
FetchTiming.IMMEDIATE,
|
||||
true,
|
||||
creationState,
|
||||
// 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.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
|
@ -66,6 +67,11 @@ public class BasicValuedCollectionPart
|
|||
return nature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluralAttributeMapping getCollectionAttribute() {
|
||||
return collectionDescriptor.getAttributeMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return selectableMapping.getJdbcMapping()::getJavaTypeDescriptor;
|
||||
|
@ -168,7 +174,9 @@ public class BasicValuedCollectionPart
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
selectableMapping.getJdbcMapping(),
|
||||
navigablePath
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -280,7 +288,8 @@ public class BasicValuedCollectionPart
|
|||
fetchablePath,
|
||||
this,
|
||||
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.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
@ -65,6 +66,11 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
|||
return Nature.ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluralAttributeMapping getCollectionAttribute() {
|
||||
return collectionDescriptor.getAttributeMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingTableExpression() {
|
||||
return containingTableName;
|
||||
|
@ -278,7 +284,8 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
|||
fetchablePath,
|
||||
this,
|
||||
FetchTiming.IMMEDIATE,
|
||||
creationState
|
||||
creationState,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -305,7 +312,9 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
null,
|
||||
type,
|
||||
collectionPath
|
||||
collectionPath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,8 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
declaringModelPart,
|
||||
tableName,
|
||||
metaColumn.getText( dialect ),
|
||||
metaColumn.getCustomReadExpression(),
|
||||
metaColumn.getCustomWriteExpression(),
|
||||
metaColumn.getSqlType(),
|
||||
metaColumn.getLength(),
|
||||
metaColumn.getPrecision(),
|
||||
|
@ -99,6 +101,8 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
declaringModelPart,
|
||||
tableName,
|
||||
keyColumn.getText( dialect ),
|
||||
keyColumn.getCustomReadExpression(),
|
||||
keyColumn.getCustomWriteExpression(),
|
||||
keyColumn.getSqlType(),
|
||||
keyColumn.getLength(),
|
||||
keyColumn.getPrecision(),
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
|
@ -80,6 +81,11 @@ public class DiscriminatedCollectionPart implements DiscriminatedAssociationMode
|
|||
return nature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluralAttributeMapping getCollectionAttribute() {
|
||||
return collectionDescriptor.getAttributeMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscriminatorMapping getDiscriminatorMapping() {
|
||||
return associationMapping.getDiscriminatorPart();
|
||||
|
|
|
@ -292,7 +292,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
|||
case STRUCT_TABLE:
|
||||
isArray = true;
|
||||
aggregateSqlTypeCode = STRUCT;
|
||||
structTypeName = bootDescriptor.getStructName();
|
||||
structTypeName = bootDescriptor.getStructName().render();
|
||||
if ( structTypeName == null ) {
|
||||
final String arrayTypeName = aggregateColumn.getSqlType( creationContext.getMetadata() );
|
||||
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
|
||||
if ( bootDescriptor.getStructName() != null ) {
|
||||
basicTypeRegistry.register( basicType, bootDescriptor.getStructName() );
|
||||
basicTypeRegistry.register( basicType, bootDescriptor.getStructName().render() );
|
||||
basicTypeRegistry.register( basicType, getMappedJavaType().getJavaTypeClass().getName() );
|
||||
}
|
||||
final BasicValue basicValue = (BasicValue) aggregateColumn.getValue();
|
||||
|
|
|
@ -94,6 +94,11 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
|||
this.sqlAliasStem = sqlAliasStem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluralAttributeMapping getCollectionAttribute() {
|
||||
return collectionDescriptor.getAttributeMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
|
|
|
@ -108,7 +108,9 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping {
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
rowIdType,
|
||||
navigablePath
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -263,7 +263,8 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
|||
fetchablePath,
|
||||
this,
|
||||
fetchTiming,
|
||||
creationState
|
||||
creationState,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -279,7 +280,9 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
versionBasicType,
|
||||
navigablePath
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -384,8 +384,10 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
null,
|
||||
selectableMapping.getJdbcMapping(),
|
||||
navigablePath,
|
||||
// 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,
|
||||
DomainResultCreationState 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(
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.sql.ast.spi.SqlSelection;
|
|||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
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.type.BasicType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
@ -69,7 +70,10 @@ public class ScalarDomainResultBuilder<T> implements ResultBuilder {
|
|||
return new BasicResult<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
null,
|
||||
( (BasicType<?>) sqlSelection.getExpressionType() )
|
||||
(BasicType<?>) sqlSelection.getExpressionType(),
|
||||
null,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -218,7 +218,9 @@ public class AnonymousTupleBasicValuedModelPart implements OwnedValuedModelPart,
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
jdbcMapping,
|
||||
navigablePath
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -270,7 +272,8 @@ public class AnonymousTupleBasicValuedModelPart implements OwnedValuedModelPart,
|
|||
fetchablePath,
|
||||
this,
|
||||
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.results.graph.DomainResult;
|
||||
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.jdbc.spi.JdbcValuesMapping;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
|
||||
|
@ -328,7 +329,10 @@ public class ResultSetMappingImpl implements ResultSetMapping {
|
|||
return new BasicResult(
|
||||
valuesArrayPosition,
|
||||
name,
|
||||
jdbcMapping
|
||||
jdbcMapping,
|
||||
null,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,9 +13,7 @@ import org.hibernate.query.results.ResultsHelper;
|
|||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
||||
import org.hibernate.query.results.ResultBuilder;
|
||||
import org.hibernate.query.results.ResultSetMappingSqlSelection;
|
||||
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.tree.from.TableGroup;
|
||||
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 static org.hibernate.query.results.ResultsHelper.impl;
|
||||
import static org.hibernate.query.results.ResultsHelper.jdbcPositionToValuesArrayPosition;
|
||||
|
||||
/**
|
||||
* CompleteResultBuilder for basic-valued ModelParts
|
||||
|
@ -93,7 +90,10 @@ public class CompleteResultBuilderBasicModelPart
|
|||
return new BasicResult<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
columnAlias,
|
||||
modelPart.getJdbcMapping()
|
||||
modelPart.getJdbcMapping(),
|
||||
navigablePath,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,10 @@ public class CompleteResultBuilderBasicValuedConverted<O,R> implements CompleteR
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
columnName,
|
||||
valueConverter.getDomainJavaType(),
|
||||
valueConverter
|
||||
valueConverter,
|
||||
null,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,10 @@ public class CompleteResultBuilderBasicValuedStandard implements CompleteResultB
|
|||
return new BasicResult<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
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.FetchParent;
|
||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
|
||||
/**
|
||||
|
@ -69,7 +70,9 @@ public class DelayedFetchBuilderBasicPart
|
|||
null,
|
||||
FetchTiming.DELAYED,
|
||||
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.results.DomainResultCreationStateImpl;
|
||||
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.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
|
@ -103,7 +102,10 @@ public class DynamicResultBuilderAttribute implements DynamicResultBuilder, Nati
|
|||
return new BasicResult<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
columnAlias,
|
||||
attributeMapping.getJdbcMapping()
|
||||
attributeMapping.getJdbcMapping(),
|
||||
null,
|
||||
false,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,10 @@ public class DynamicResultBuilderBasicConverted<O,R> implements DynamicResultBui
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
columnAlias,
|
||||
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.
|
||||
assert javaType != null;
|
||||
|
||||
return new BasicResult( sqlSelection.getValuesArrayPosition(), resultAlias, javaType, converter );
|
||||
return new BasicResult(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
resultAlias,
|
||||
javaType,
|
||||
converter,
|
||||
null,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,7 +17,6 @@ import org.hibernate.query.results.BasicValuedFetchBuilder;
|
|||
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
||||
import org.hibernate.query.results.FetchBuilder;
|
||||
import org.hibernate.query.results.ResultsHelper;
|
||||
import org.hibernate.query.results.ResultSetMappingSqlSelection;
|
||||
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
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 static org.hibernate.query.results.ResultsHelper.impl;
|
||||
import static org.hibernate.query.results.ResultsHelper.jdbcPositionToValuesArrayPosition;
|
||||
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
|
||||
|
||||
/**
|
||||
|
@ -118,7 +116,8 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, BasicVal
|
|||
fetchPath,
|
||||
fetchable,
|
||||
FetchTiming.IMMEDIATE,
|
||||
domainResultCreationState
|
||||
domainResultCreationState,
|
||||
!sqlSelection.isVirtual()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -174,7 +174,10 @@ public class SelfRenderingFunctionSqlAstExpression
|
|||
.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
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.DomainResultCreationState;
|
||||
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.
|
||||
|
@ -33,7 +34,9 @@ public class ExpressionDomainResultProducer implements DomainResultProducer<Obje
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
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.JdbcParameterBindings;
|
||||
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.spi.ListResultsConsumer;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
|
@ -402,7 +403,8 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
null,
|
||||
identifierMapping,
|
||||
FetchTiming.IMMEDIATE,
|
||||
null
|
||||
null,
|
||||
false
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -105,14 +105,17 @@ public class SqlAstQueryPartProcessingStateImpl
|
|||
else {
|
||||
throw new IllegalArgumentException( "Illegal expression passed for nested fetching: " + expression );
|
||||
}
|
||||
final int selectableIndex = nestingFetchParent.getReferencedMappingType().getSelectableIndex( selectableName );
|
||||
if ( selectableIndex != -1 ) {
|
||||
return expression.createSqlSelection(
|
||||
-1,
|
||||
nestingFetchParent.getReferencedMappingType().getSelectableIndex( selectableName ),
|
||||
selectableIndex,
|
||||
javaType,
|
||||
true,
|
||||
typeConfiguration
|
||||
);
|
||||
}
|
||||
}
|
||||
final Map<Expression, Object> selectionMap;
|
||||
if ( deduplicateSelectionItems ) {
|
||||
if ( sqlSelectionMap == null ) {
|
||||
|
|
|
@ -108,7 +108,10 @@ public class SqmParameterInterpretation implements Expression, DomainResultProdu
|
|||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
jdbcMapping.getMappedJavaType(),
|
||||
converter
|
||||
converter,
|
||||
null,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,26 +38,6 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
|||
|
||||
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(
|
||||
int valuesArrayPosition,
|
||||
FetchParent fetchParent,
|
||||
|
@ -65,7 +45,7 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
|||
BasicValuedModelPart valuedMapping,
|
||||
FetchTiming fetchTiming,
|
||||
DomainResultCreationState creationState,
|
||||
boolean coerceResultType) {
|
||||
boolean unwrapRowProcessingState) {
|
||||
//noinspection unchecked
|
||||
this(
|
||||
valuesArrayPosition,
|
||||
|
@ -76,49 +56,8 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
|||
fetchTiming,
|
||||
true,
|
||||
creationState,
|
||||
coerceResultType
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
false,
|
||||
unwrapRowProcessingState
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -131,7 +70,8 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
|||
FetchTiming fetchTiming,
|
||||
boolean canBasicPartFetchBeDelayed,
|
||||
DomainResultCreationState creationState,
|
||||
boolean coerceResultType) {
|
||||
boolean coerceResultType,
|
||||
boolean unwrapRowProcessingState) {
|
||||
this.navigablePath = fetchablePath;
|
||||
|
||||
this.fetchParent = fetchParent;
|
||||
|
@ -149,10 +89,10 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
|
|||
}
|
||||
else {
|
||||
if (coerceResultType) {
|
||||
this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
|
||||
this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter, unwrapRowProcessingState );
|
||||
}
|
||||
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,
|
||||
resultVariable,
|
||||
jdbcMapping,
|
||||
null
|
||||
null,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -48,81 +50,38 @@ public class BasicResult<T> implements DomainResult<T>, BasicResultGraphNode<T>
|
|||
int jdbcValuesArrayPosition,
|
||||
String resultVariable,
|
||||
JdbcMapping jdbcMapping,
|
||||
boolean coerceResultType) {
|
||||
NavigablePath navigablePath,
|
||||
boolean coerceResultType,
|
||||
boolean unwrapRowProcessingState) {
|
||||
//noinspection unchecked
|
||||
this(
|
||||
jdbcValuesArrayPosition,
|
||||
resultVariable,
|
||||
jdbcMapping.getJavaTypeDescriptor(),
|
||||
jdbcMapping.getValueConverter(),
|
||||
null,
|
||||
coerceResultType
|
||||
navigablePath,
|
||||
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(
|
||||
int valuesArrayPosition,
|
||||
String resultVariable,
|
||||
JavaType<T> javaType,
|
||||
BasicValueConverter<T,?> valueConverter,
|
||||
NavigablePath navigablePath,
|
||||
boolean coerceResultType) {
|
||||
boolean coerceResultType,
|
||||
boolean unwrapRowProcessingState) {
|
||||
this.resultVariable = resultVariable;
|
||||
this.javaType = javaType;
|
||||
this.navigablePath = navigablePath;
|
||||
|
||||
if ( coerceResultType ) {
|
||||
this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
|
||||
this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter, unwrapRowProcessingState );
|
||||
}
|
||||
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 JavaType<J> assembledJavaType;
|
||||
private final BasicValueConverter<J,?> valueConverter;
|
||||
private final boolean unwrapRowProcessingState;
|
||||
|
||||
public BasicResultAssembler(
|
||||
int valuesArrayPosition,
|
||||
JavaType<J> assembledJavaType) {
|
||||
this( valuesArrayPosition, assembledJavaType, null );
|
||||
public BasicResultAssembler(int valuesArrayPosition, JavaType<J> assembledJavaType) {
|
||||
this( valuesArrayPosition, assembledJavaType, null, false );
|
||||
}
|
||||
|
||||
public BasicResultAssembler(
|
||||
int valuesArrayPosition,
|
||||
JavaType<J> assembledJavaType,
|
||||
BasicValueConverter<J, ?> valueConverter) {
|
||||
BasicValueConverter<J, ?> valueConverter,
|
||||
boolean unwrapRowProcessingState) {
|
||||
this.valuesArrayPosition = valuesArrayPosition;
|
||||
this.assembledJavaType = assembledJavaType;
|
||||
this.valueConverter = valueConverter;
|
||||
this.unwrapRowProcessingState = unwrapRowProcessingState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to the raw value (unconverted, if a converter applied)
|
||||
*/
|
||||
public Object extractRawValue(RowProcessingState rowProcessingState) {
|
||||
if ( unwrapRowProcessingState ) {
|
||||
rowProcessingState = rowProcessingState.unwrap();
|
||||
}
|
||||
return rowProcessingState.getJdbcValue( valuesArrayPosition );
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,9 @@ public class CoercingResultAssembler<J> extends BasicResultAssembler<J> {
|
|||
public CoercingResultAssembler(
|
||||
int valuesArrayPosition,
|
||||
JavaType<J> assembledJavaType,
|
||||
BasicValueConverter<J, ?> valueConverter) {
|
||||
super( valuesArrayPosition, assembledJavaType, valueConverter );
|
||||
BasicValueConverter<J, ?> valueConverter,
|
||||
boolean nestedInAggregateComponent) {
|
||||
super( valuesArrayPosition, assembledJavaType, valueConverter, nestedInAggregateComponent );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,7 +32,7 @@ public class CoercingResultAssembler<J> extends BasicResultAssembler<J> {
|
|||
@Override
|
||||
public Object extractRawValue(RowProcessingState rowProcessingState) {
|
||||
return assembledJavaType.coerce(
|
||||
rowProcessingState.getJdbcValue( valuesArrayPosition ),
|
||||
super.extractRawValue( rowProcessingState ),
|
||||
rowProcessingState.getSession()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -74,7 +74,8 @@ public class EmbeddableExpressionResultImpl<T> extends AbstractFetchParent imple
|
|||
resolveNavigablePath( attribute ),
|
||||
attribute,
|
||||
FetchTiming.IMMEDIATE,
|
||||
creationState
|
||||
creationState,
|
||||
!sqlSelection.isVirtual()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,11 @@ public class NestedRowProcessingState extends BaseExecutionContext implements Ro
|
|||
return jdbcValue == null ? null : jdbcValue[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowProcessingState unwrap() {
|
||||
return processingState;
|
||||
}
|
||||
|
||||
// -- delegate the rest
|
||||
|
||||
@Override
|
||||
|
|
|
@ -68,4 +68,12 @@ public interface RowProcessingState extends ExecutionContext {
|
|||
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 ) {
|
||||
return null;
|
||||
}
|
||||
if ( Boolean.class.isAssignableFrom( type ) ) {
|
||||
if ( Boolean.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||
return (X) value;
|
||||
}
|
||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
||||
|
|
|
@ -47,7 +47,7 @@ public class ByteJavaType extends AbstractClassJavaType<Byte>
|
|||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
||||
if ( Byte.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||
return (X) value;
|
||||
}
|
||||
if ( Short.class.isAssignableFrom( type ) ) {
|
||||
|
|
|
@ -44,7 +44,7 @@ public class CharacterJavaType extends AbstractClassJavaType<Character> implemen
|
|||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( Character.class.isAssignableFrom( type ) ) {
|
||||
if ( Character.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||
return (X) value;
|
||||
}
|
||||
if ( String.class.isAssignableFrom( type ) ) {
|
||||
|
|
|
@ -51,7 +51,7 @@ public class DoubleJavaType extends AbstractClassJavaType<Double> implements
|
|||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( Double.class.isAssignableFrom( type ) ) {
|
||||
if ( Double.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||
return (X) value;
|
||||
}
|
||||
if ( Float.class.isAssignableFrom( type ) ) {
|
||||
|
|
|
@ -50,7 +50,7 @@ public class FloatJavaType extends AbstractClassJavaType<Float> implements Primi
|
|||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( Float.class.isAssignableFrom( type ) ) {
|
||||
if ( Float.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||
return (X) value;
|
||||
}
|
||||
if ( Double.class.isAssignableFrom( type ) ) {
|
||||
|
|
|
@ -47,7 +47,7 @@ public class IntegerJavaType extends AbstractClassJavaType<Integer>
|
|||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( Integer.class.isAssignableFrom( type ) ) {
|
||||
if ( Integer.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||
return (X) value;
|
||||
}
|
||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
||||
|
|
|
@ -47,7 +47,7 @@ public class LongJavaType extends AbstractClassJavaType<Long>
|
|||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( Long.class.isAssignableFrom( type ) ) {
|
||||
if ( Long.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||
return (X) value;
|
||||
}
|
||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
||||
|
|
|
@ -57,7 +57,7 @@ public class ShortJavaType extends AbstractClassJavaType<Short>
|
|||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( Short.class.isAssignableFrom( type ) ) {
|
||||
if ( Short.class.isAssignableFrom( type ) || type == Object.class ) {
|
||||
return (X) value;
|
||||
}
|
||||
if ( Byte.class.isAssignableFrom( type ) ) {
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.hibernate.dialect.StructHelper;
|
|||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
|
@ -107,23 +106,58 @@ public class ArrayJdbcType implements JdbcType {
|
|||
|
||||
@Override
|
||||
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();
|
||||
//noinspection unchecked
|
||||
final JavaType<Object> javaType = (JavaType<Object>) binder.getJavaType();
|
||||
if ( elementJdbcType instanceof AggregateJdbcType ) {
|
||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) elementJdbcType;
|
||||
final Object[] domainObjects = ( javaType ).unwrap(
|
||||
final Object[] domainObjects = javaType.unwrap(
|
||||
value,
|
||||
Object[].class,
|
||||
options
|
||||
);
|
||||
final Object[] objects = new Object[domainObjects.length];
|
||||
for ( int i = 0; i < domainObjects.length; i++ ) {
|
||||
objects[i] = aggregateJdbcType.createJdbcValue( domainObjects[i], options );
|
||||
objects[i] = elementBinder.getBindValue( domainObjects[i], options );
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
@ -174,6 +208,8 @@ public class ArrayJdbcType implements JdbcType {
|
|||
|
||||
@Override
|
||||
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 ) {
|
||||
|
||||
@Override
|
||||
|
@ -193,49 +229,20 @@ public class ArrayJdbcType implements JdbcType {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getBindValue(X value, WrapperOptions options) throws SQLException {
|
||||
return ( (ArrayJdbcType) getJdbcType() ).getArray( this, elementBinder, value, options );
|
||||
}
|
||||
|
||||
private java.sql.Array getArray(X value, WrapperOptions options) throws SQLException {
|
||||
final JdbcType elementJdbcType = ( (ArrayJdbcType) getJdbcType() ).getElementJdbcType();
|
||||
final Object[] objects = ArrayJdbcType.this.getArray( this, value, options );
|
||||
final ArrayJdbcType arrayJdbcType = (ArrayJdbcType) getJdbcType();
|
||||
final Object[] objects = arrayJdbcType.getArray( this, elementBinder, value, options );
|
||||
|
||||
final SharedSessionContractImplementor session = options.getSession();
|
||||
final String typeName = getElementTypeName( elementJdbcType, session );
|
||||
final String typeName = arrayJdbcType.getElementTypeName( getJavaType(), session );
|
||||
return session.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection()
|
||||
.createArrayOf( typeName, objects );
|
||||
}
|
||||
|
||||
private String getElementTypeName(JdbcType elementJdbcType, 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<X> elementJavaType;
|
||||
if ( getJavaType() instanceof ByteArrayJavaType ) {
|
||||
// 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
|
||||
public String toString() {
|
||||
return "ArrayTypeDescriptor";
|
||||
return "ArrayTypeDescriptor(" + getElementJdbcType().toString() + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,18 +20,21 @@ import jakarta.persistence.Entity;
|
|||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
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)
|
||||
public class StructComponentCollectionErrorTest {
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructuralArrays.class)
|
||||
public class StructComponentAssociationErrorTest {
|
||||
|
||||
@Test
|
||||
@JiraKey( "HHH-15831" )
|
||||
public void testError1() {
|
||||
public void testOneToOneMappedBy() {
|
||||
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
||||
try {
|
||||
new MetadataSources( ssr )
|
||||
|
@ -41,7 +44,7 @@ public class StructComponentCollectionErrorTest {
|
|||
Assertions.fail( "Expected a failure" );
|
||||
}
|
||||
catch (MappingException ex) {
|
||||
assertThat( ex.getMessage(), containsString( "author.favoriteBook" ) );
|
||||
assertThat( ex.getMessage(), containsString( "authors.favoriteBook" ) );
|
||||
}
|
||||
finally {
|
||||
StandardServiceRegistryBuilder.destroy( ssr );
|
||||
|
@ -56,19 +59,21 @@ public class StructComponentCollectionErrorTest {
|
|||
@GeneratedValue
|
||||
private Long id;
|
||||
private String title;
|
||||
private Person1 author;
|
||||
private Person1[] authors;
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
private Book1 favoredBook;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
@Struct(name = "person_type")
|
||||
public static class Person1 {
|
||||
private String name;
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@OneToOne(mappedBy = "favoredBook", fetch = FetchType.LAZY)
|
||||
private Book1 favoriteBook;
|
||||
}
|
||||
|
||||
@Test
|
||||
@JiraKey( "HHH-15831" )
|
||||
public void testError2() {
|
||||
public void testOneToManyMappedBy() {
|
||||
final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry();
|
||||
try {
|
||||
new MetadataSources( ssr )
|
||||
|
@ -78,7 +83,7 @@ public class StructComponentCollectionErrorTest {
|
|||
Assertions.fail( "Expected a failure" );
|
||||
}
|
||||
catch (MappingException ex) {
|
||||
assertThat( ex.getMessage(), containsString( "author.bookCollection" ) );
|
||||
assertThat( ex.getMessage(), containsString( "authors.bookCollection" ) );
|
||||
}
|
||||
finally {
|
||||
StandardServiceRegistryBuilder.destroy( ssr );
|
||||
|
@ -93,15 +98,54 @@ public class StructComponentCollectionErrorTest {
|
|||
@GeneratedValue
|
||||
private Long id;
|
||||
private String title;
|
||||
private Person2 author;
|
||||
private Person2[] authors;
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
private Book2 mainBook;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
@Struct(name = "person_type")
|
||||
public static class Person2 {
|
||||
private String name;
|
||||
@OneToMany
|
||||
@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( "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