introduce AnnotatedColumns

This commit is contained in:
Gavin King 2022-10-30 16:49:46 +01:00
parent 653bf987bd
commit ec336f3a23
22 changed files with 539 additions and 425 deletions

View File

@ -3275,9 +3275,9 @@ protected void createBackReferences() {
&& !collectionBinding.isInverse() && !collectionBinding.isInverse()
&& !collectionBinding.getKey().isNullable() ) { && !collectionBinding.getKey().isNullable() ) {
// for non-inverse one-to-many, with a not-null fk, add a backref! // for non-inverse one-to-many, with a not-null fk, add a backref!
String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName(); final String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName();
PersistentClass referenced = getReferencedEntityBinding( entityName ); final PersistentClass referenced = getReferencedEntityBinding( entityName );
Backref prop = new Backref(); final Backref prop = new Backref();
prop.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "Backref" ); prop.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "Backref" );
prop.setUpdateable( false ); prop.setUpdateable( false );
prop.setSelectable( false ); prop.setSelectable( false );
@ -3298,13 +3298,13 @@ protected void createBackReferences() {
protected void bindCollectionKey() { protected void bindCollectionKey() {
final PluralAttributeKeySource keySource = getPluralAttributeSource().getKeySource(); final PluralAttributeKeySource keySource = getPluralAttributeSource().getKeySource();
final String propRef = keySource.getReferencedPropertyName(); final String referencedPropertyName = keySource.getReferencedPropertyName();
getCollectionBinding().setReferencedPropertyName( propRef ); getCollectionBinding().setReferencedPropertyName( referencedPropertyName );
final PersistentClass owner = getCollectionBinding().getOwner(); final PersistentClass owner = getCollectionBinding().getOwner();
final KeyValue keyVal = propRef == null final KeyValue keyVal = referencedPropertyName == null
? owner.getIdentifier() ? owner.getIdentifier()
: (KeyValue) owner.getRecursiveProperty( propRef ).getValue(); : (KeyValue) owner.getRecursiveProperty( referencedPropertyName ).getValue();
final DependantValue key = new DependantValue( final DependantValue key = new DependantValue(
mappingDocument, mappingDocument,
getCollectionBinding().getCollectionTable(), getCollectionBinding().getCollectionTable(),

View File

@ -42,6 +42,7 @@
import static org.hibernate.cfg.BinderHelper.getRelativePath; import static org.hibernate.cfg.BinderHelper.getRelativePath;
import static org.hibernate.internal.util.StringHelper.isEmpty; import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.StringHelper.qualify;
/** /**
* A mapping to a column, logically representing a * A mapping to a column, logically representing a
@ -67,8 +68,9 @@ public class AnnotatedColumn {
private Column mappingColumn; private Column mappingColumn;
private boolean insertable = true; private boolean insertable = true;
private boolean updatable = true; private boolean updatable = true;
private String explicitTableName; private String explicitTableName; // the JPA @Column annotation lets you specify a table name
protected Map<String, Join> joins; protected Map<String, Join> joins;
@Deprecated // use AnnotatedColumns.propertyHolder
protected PropertyHolder propertyHolder; protected PropertyHolder propertyHolder;
private boolean isImplicit; private boolean isImplicit;
public String sqlType; public String sqlType;
@ -81,7 +83,6 @@ public class AnnotatedColumn {
private boolean nullable = true; private boolean nullable = true;
private String formulaString; private String formulaString;
private Formula formula; private Formula formula;
private Table table;
private String readExpression; private String readExpression;
private String writeExpression; private String writeExpression;
@ -91,8 +92,10 @@ public class AnnotatedColumn {
private String comment; private String comment;
private String checkConstraint; private String checkConstraint;
public void setTable(Table table) { private AnnotatedColumns parent;
this.table = table;
void setParent(AnnotatedColumns parent) {
this.parent = parent;
} }
public String getLogicalColumnName() { public String getLogicalColumnName() {
@ -123,23 +126,16 @@ public boolean isFormula() {
return isNotEmpty( formulaString ); return isNotEmpty( formulaString );
} }
@SuppressWarnings("UnusedDeclaration")
public String getFormulaString() { public String getFormulaString() {
return formulaString; return formulaString;
} }
@SuppressWarnings("UnusedDeclaration")
public String getExplicitTableName() { public String getExplicitTableName() {
return explicitTableName; return explicitTableName;
} }
public void setExplicitTableName(String explicitTableName) { public void setExplicitTableName(String explicitTableName) {
if ( "``".equals( explicitTableName ) ) { this.explicitTableName = "``".equals( explicitTableName ) ? "" : explicitTableName;
this.explicitTableName = "";
}
else {
this.explicitTableName = explicitTableName;
}
} }
public void setFormula(String formula) { public void setFormula(String formula) {
@ -371,8 +367,8 @@ public AttributePath getAttributePath() {
public boolean isCollectionElement() { public boolean isCollectionElement() {
// if the propertyHolder is a collection, assume the // if the propertyHolder is a collection, assume the
// @Column refers to the element column // @Column refers to the element column
return !propertyHolder.isComponent() return !getPropertyHolder().isComponent()
&& !propertyHolder.isEntity(); && !getPropertyHolder().isEntity();
} }
@Override @Override
@ -426,9 +422,10 @@ public void setJoins(Map<String, Join> joins) {
} }
public PropertyHolder getPropertyHolder() { public PropertyHolder getPropertyHolder() {
return propertyHolder; return propertyHolder; //TODO: change this to delegate to the parent
} }
@Deprecated // use AnnotatedColumns.setPropertyHolder() instead
public void setPropertyHolder(PropertyHolder propertyHolder) { public void setPropertyHolder(PropertyHolder propertyHolder) {
this.propertyHolder = propertyHolder; this.propertyHolder = propertyHolder;
} }
@ -437,12 +434,16 @@ protected void setMappingColumn(Column mappingColumn) {
this.mappingColumn = mappingColumn; this.mappingColumn = mappingColumn;
} }
//TODO: move this operation to AnnotatedColumns!!
public void linkWithValue(SimpleValue value) { public void linkWithValue(SimpleValue value) {
if ( formula != null ) { if ( formula != null ) {
value.addFormula( formula ); value.addFormula( formula );
} }
else { else {
table = value.getTable(); final Table table = value.getTable();
if ( parent != null ) {
parent.setTableInternal( table );
}
getMappingColumn().setValue( value ); getMappingColumn().setValue( value );
value.addColumn( getMappingColumn(), insertable, updatable ); value.addColumn( getMappingColumn(), insertable, updatable );
table.addColumn( getMappingColumn() ); table.addColumn( getMappingColumn() );
@ -494,31 +495,25 @@ public MetadataBuildingContext getBuildingContext() {
* @throws AnnotationException missing secondary table * @throws AnnotationException missing secondary table
*/ */
public Table getTable() { public Table getTable() {
if ( table != null ) { return parent.getTable();
return table;
}
else if ( isSecondary() ) {
return getJoin().getTable();
}
else {
return propertyHolder.getTable();
}
} }
//TODO: move to AnnotatedColumns
public boolean isSecondary() { public boolean isSecondary() {
if ( propertyHolder == null ) { if ( propertyHolder == null ) {
throw new AssertionFailure( "Should not call getTable() on column w/o persistent class defined" ); throw new AssertionFailure( "Should not call isSecondary() on column w/o persistent class defined" );
} }
return isNotEmpty( explicitTableName ) return isNotEmpty( explicitTableName )
&& !propertyHolder.getTable().getName().equals( explicitTableName ); && !getPropertyHolder().getTable().getName().equals( explicitTableName );
} }
//TODO: move to AnnotatedColumns
public Join getJoin() { public Join getJoin() {
Join join = joins.get( explicitTableName ); Join join = joins.get( explicitTableName );
if ( join == null ) { if ( join == null ) {
// annotation binding seems to use logical and physical naming somewhat inconsistently... // annotation binding seems to use logical and physical naming somewhat inconsistently...
final String physicalTableName = getBuildingContext().getMetadataCollector().getPhysicalTableName( explicitTableName ); final String physicalTableName = getBuildingContext().getMetadataCollector()
.getPhysicalTableName( explicitTableName );
if ( physicalTableName != null ) { if ( physicalTableName != null ) {
join = joins.get( physicalTableName ); join = joins.get( physicalTableName );
} }
@ -526,7 +521,7 @@ public Join getJoin() {
if ( join == null ) { if ( join == null ) {
throw new AnnotationException( throw new AnnotationException(
"Secondary table '" + explicitTableName + "' for property '" + propertyHolder.getClassName() "Secondary table '" + explicitTableName + "' for property '" + getPropertyHolder().getClassName()
+ "' is not declared (use '@SecondaryTable' to declare the secondary table)" + "' is not declared (use '@SecondaryTable' to declare the secondary table)"
); );
} }
@ -544,7 +539,7 @@ public void forceNotNull() {
mappingColumn.setNullable( false ); mappingColumn.setNullable( false );
} }
public static AnnotatedColumn[] buildFormulaFromAnnotation( public static AnnotatedColumns buildFormulaFromAnnotation(
org.hibernate.annotations.Formula formulaAnn, org.hibernate.annotations.Formula formulaAnn,
Comment commentAnn, Comment commentAnn,
Nullability nullability, Nullability nullability,
@ -564,7 +559,7 @@ public static AnnotatedColumn[] buildFormulaFromAnnotation(
); );
} }
public static AnnotatedColumn[] buildColumnFromNoAnnotation( public static AnnotatedColumns buildColumnFromNoAnnotation(
Comment commentAnn, Comment commentAnn,
Nullability nullability, Nullability nullability,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
@ -582,7 +577,7 @@ public static AnnotatedColumn[] buildColumnFromNoAnnotation(
); );
} }
public static AnnotatedColumn[] buildColumnFromAnnotation( public static AnnotatedColumns buildColumnFromAnnotation(
jakarta.persistence.Column column, jakarta.persistence.Column column,
Comment commentAnn, Comment commentAnn,
Nullability nullability, Nullability nullability,
@ -602,7 +597,7 @@ public static AnnotatedColumn[] buildColumnFromAnnotation(
); );
} }
public static AnnotatedColumn[] buildColumnsFromAnnotations( public static AnnotatedColumns buildColumnsFromAnnotations(
jakarta.persistence.Column[] columns, jakarta.persistence.Column[] columns,
Comment commentAnn, Comment commentAnn,
Nullability nullability, Nullability nullability,
@ -623,7 +618,7 @@ public static AnnotatedColumn[] buildColumnsFromAnnotations(
); );
} }
public static AnnotatedColumn[] buildColumnsFromAnnotations( public static AnnotatedColumns buildColumnsFromAnnotations(
jakarta.persistence.Column[] columns, jakarta.persistence.Column[] columns,
Comment commentAnn, Comment commentAnn,
Nullability nullability, Nullability nullability,
@ -645,7 +640,7 @@ public static AnnotatedColumn[] buildColumnsFromAnnotations(
); );
} }
public static AnnotatedColumn[] buildColumnOrFormulaFromAnnotation( public static AnnotatedColumns buildColumnOrFormulaFromAnnotation(
jakarta.persistence.Column column, jakarta.persistence.Column column,
org.hibernate.annotations.Formula formulaAnn, org.hibernate.annotations.Formula formulaAnn,
Comment commentAnn, Comment commentAnn,
@ -667,7 +662,7 @@ public static AnnotatedColumn[] buildColumnOrFormulaFromAnnotation(
); );
} }
public static AnnotatedColumn[] buildColumnsOrFormulaFromAnnotation( public static AnnotatedColumns buildColumnsOrFormulaFromAnnotation(
jakarta.persistence.Column[] columns, jakarta.persistence.Column[] columns,
org.hibernate.annotations.Formula formulaAnn, org.hibernate.annotations.Formula formulaAnn,
Comment comment, Comment comment,
@ -685,10 +680,13 @@ public static AnnotatedColumn[] buildColumnsOrFormulaFromAnnotation(
formulaColumn.setBuildingContext( context ); formulaColumn.setBuildingContext( context );
formulaColumn.setPropertyHolder( propertyHolder ); formulaColumn.setPropertyHolder( propertyHolder );
formulaColumn.bind(); formulaColumn.bind();
return new AnnotatedColumn[] { formulaColumn }; final AnnotatedColumns result = new AnnotatedColumns();
result.setPropertyHolder( propertyHolder );
result.setColumns(new AnnotatedColumn[] {formulaColumn});
return result;
} }
else { else {
jakarta.persistence.Column[] actualCols = overrideColumns( columns, propertyHolder, inferredData); final jakarta.persistence.Column[] actualCols = overrideColumns( columns, propertyHolder, inferredData );
if ( actualCols == null ) { if ( actualCols == null ) {
return buildImplicitColumn( return buildImplicitColumn(
inferredData, inferredData,
@ -719,7 +717,7 @@ private static jakarta.persistence.Column[] overrideColumns(
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData ) { PropertyData inferredData ) {
final jakarta.persistence.Column[] overriddenCols = propertyHolder.getOverriddenColumn( final jakarta.persistence.Column[] overriddenCols = propertyHolder.getOverriddenColumn(
StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() ) qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
); );
if ( overriddenCols != null ) { if ( overriddenCols != null ) {
//check for overridden first //check for overridden first
@ -739,7 +737,7 @@ private static jakarta.persistence.Column[] overrideColumns(
} }
} }
private static AnnotatedColumn[] buildExplicitColumns( private static AnnotatedColumns buildExplicitColumns(
Comment comment, Comment comment,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData, PropertyData inferredData,
@ -775,7 +773,10 @@ private static AnnotatedColumn[] buildExplicitColumns(
tableName tableName
); );
} }
return columns; final AnnotatedColumns result = new AnnotatedColumns();
result.setPropertyHolder(propertyHolder);
result.setColumns(columns);
return result;
} }
private static AnnotatedColumn buildColumn( private static AnnotatedColumn buildColumn(
@ -884,8 +885,8 @@ private void extractDataFromPropertyData(PropertyData inferredData) {
if ( inferredData != null ) { if ( inferredData != null ) {
XProperty property = inferredData.getProperty(); XProperty property = inferredData.getProperty();
if ( property != null ) { if ( property != null ) {
if ( propertyHolder.isComponent() ) { if ( getPropertyHolder().isComponent() ) {
processColumnTransformerExpressions( propertyHolder.getOverriddenColumnTransformer( logicalColumnName ) ); processColumnTransformerExpressions( getPropertyHolder().getOverriddenColumnTransformer( logicalColumnName ) );
} }
processColumnTransformerExpressions( property.getAnnotation( ColumnTransformer.class ) ); processColumnTransformerExpressions( property.getAnnotation( ColumnTransformer.class ) );
ColumnTransformers annotations = property.getAnnotation( ColumnTransformers.class ); ColumnTransformers annotations = property.getAnnotation( ColumnTransformers.class );
@ -909,7 +910,7 @@ private void processColumnTransformerExpressions(ColumnTransformer annotation) {
} }
} }
private static AnnotatedColumn[] buildImplicitColumn( private static AnnotatedColumns buildImplicitColumn(
PropertyData inferredData, PropertyData inferredData,
String suffixForDefaultColumnName, String suffixForDefaultColumnName,
Map<String, Join> secondaryTables, Map<String, Join> secondaryTables,
@ -917,8 +918,9 @@ private static AnnotatedColumn[] buildImplicitColumn(
Comment comment, Comment comment,
Nullability nullability, Nullability nullability,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final AnnotatedColumn[] columns = new AnnotatedColumn[1]; final AnnotatedColumns result = new AnnotatedColumns();
columns[0] = bindImplicitColumn( result.setPropertyHolder( propertyHolder );
final AnnotatedColumn column = bindImplicitColumn(
inferredData, inferredData,
suffixForDefaultColumnName, suffixForDefaultColumnName,
secondaryTables, secondaryTables,
@ -927,7 +929,8 @@ private static AnnotatedColumn[] buildImplicitColumn(
nullability, nullability,
context context
); );
return columns; result.setColumns( new AnnotatedColumn[] { column } );
return result;
} }
private static AnnotatedColumn bindImplicitColumn( private static AnnotatedColumn bindImplicitColumn(
@ -968,9 +971,8 @@ private static AnnotatedColumn bindImplicitColumn(
} }
public static void checkPropertyConsistency(AnnotatedColumn[] columns, String propertyName) { public static void checkPropertyConsistency(AnnotatedColumn[] columns, String propertyName) {
int nbrOfColumns = columns.length; if ( columns.length > 1 ) {
if ( nbrOfColumns > 1 ) { for (int currentIndex = 1; currentIndex < columns.length; currentIndex++) {
for (int currentIndex = 1; currentIndex < nbrOfColumns; currentIndex++) {
if ( !columns[currentIndex].isFormula() && !columns[currentIndex - 1].isFormula() ) { if ( !columns[currentIndex].isFormula() && !columns[currentIndex - 1].isFormula() ) {
if ( columns[currentIndex].isNullable() != columns[currentIndex - 1].isNullable() ) { if ( columns[currentIndex].isNullable() != columns[currentIndex - 1].isNullable() ) {
throw new AnnotationException( throw new AnnotationException(

View File

@ -0,0 +1,68 @@
package org.hibernate.cfg;
import org.hibernate.mapping.Table;
/**
* A list of columns that are mapped to a single Java property
* or field. This is a slightly uncomfortable abstraction here,
* because this concept is arguably missing from JPA (where
* there's no equivalent of the Hibernate-defined
* {@link org.hibernate.annotations.Columns} annotation) and
* so JPA lets each {@link jakarta.persistence.Column} specify
* its own {@link jakarta.persistence.Column#table table}.
* That leaves us having to enforce the requirement that every
* column mapped to a given property must belong to the same
* table.
*
* @author Gavin King
*/
public class AnnotatedColumns {
private AnnotatedColumn[] columns;
private Table table;
private PropertyHolder propertyHolder;
public void setColumns(AnnotatedColumn[] columns) {
this.columns = columns;
if ( columns != null ) {
for ( AnnotatedColumn column : columns ) {
column.setParent( this );
}
}
}
public AnnotatedColumn[] getColumns() {
return columns;
}
public PropertyHolder getPropertyHolder() {
return propertyHolder;
}
public void setPropertyHolder(PropertyHolder propertyHolder) {
this.propertyHolder = propertyHolder;
}
public Table getTable() {
if ( table != null ) {
return table;
}
else {
// all the columns have to be mapped to the same table
// even though at the annotation level it looks like
// they could each specify a different table
final AnnotatedColumn firstColumn = columns[0];
return firstColumn.isSecondary()
? firstColumn.getJoin().getTable()
: firstColumn.getPropertyHolder().getTable();
}
}
public void setTable(Table table) {
this.table = table;
}
@Deprecated
void setTableInternal(Table table) {
this.table = table;
}
}

View File

@ -549,6 +549,7 @@ public String toString() {
} }
public void setParent(AnnotatedJoinColumns parent) { public void setParent(AnnotatedJoinColumns parent) {
super.setParent( parent );
this.parent = parent; this.parent = parent;
} }
} }

View File

@ -45,7 +45,7 @@
* *
* @author Gavin King * @author Gavin King
*/ */
public class AnnotatedJoinColumns { public class AnnotatedJoinColumns extends AnnotatedColumns {
private AnnotatedJoinColumn[] columns; private AnnotatedJoinColumn[] columns;
private PropertyHolder propertyHolder; private PropertyHolder propertyHolder;
@ -60,8 +60,6 @@ public class AnnotatedJoinColumns {
private boolean elementCollection; private boolean elementCollection;
private String manyToManyOwnerSideEntityName; private String manyToManyOwnerSideEntityName;
public AnnotatedJoinColumns() {}
public static AnnotatedJoinColumns buildJoinColumnsOrFormulas( public static AnnotatedJoinColumns buildJoinColumnsOrFormulas(
JoinColumnOrFormula[] joinColumnOrFormulas, JoinColumnOrFormula[] joinColumnOrFormulas,
String mappedBy, String mappedBy,
@ -204,7 +202,13 @@ public AnnotatedJoinColumn[] getColumns() {
return columns; return columns;
} }
@Override
public void setColumns(AnnotatedColumn[] columns) {
throw new UnsupportedOperationException( "wrong sort of columns" );
}
public void setColumns(AnnotatedJoinColumn[] columns) { public void setColumns(AnnotatedJoinColumn[] columns) {
super.setColumns( columns );
this.columns = columns; this.columns = columns;
if ( columns != null ) { if ( columns != null ) {
for ( AnnotatedJoinColumn column : columns ) { for ( AnnotatedJoinColumn column : columns ) {

View File

@ -1118,7 +1118,7 @@ private static void buildProperty(
entityBinder, entityBinder,
context context
).extractMetadata(); ).extractMetadata();
AnnotatedColumn[] columns = columnsBuilder.getColumns(); AnnotatedColumns columns = columnsBuilder.getColumns();
AnnotatedJoinColumns joinColumns = columnsBuilder.getJoinColumns(); AnnotatedJoinColumns joinColumns = columnsBuilder.getJoinColumns();
final PropertyBinder propertyBinder = new PropertyBinder(); final PropertyBinder propertyBinder = new PropertyBinder();
@ -1252,7 +1252,7 @@ private static void bindVersionProperty(
MetadataBuildingContext context, MetadataBuildingContext context,
Map<XClass, InheritanceState> inheritanceStatePerClass, Map<XClass, InheritanceState> inheritanceStatePerClass,
XProperty property, XProperty property,
AnnotatedColumn[] columns, AnnotatedColumns columns,
PropertyBinder propertyBinder) { PropertyBinder propertyBinder) {
if (isIdentifierMapper) { if (isIdentifierMapper) {
throw new AnnotationException( throw new AnnotationException(
@ -1303,7 +1303,7 @@ private static void bindVersionProperty(
} }
} }
private static AnnotatedColumn[] bindBasic( private static AnnotatedColumns bindBasic(
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
Nullability nullability, Nullability nullability,
PropertyData inferredData, PropertyData inferredData,
@ -1315,14 +1315,14 @@ private static AnnotatedColumn[] bindBasic(
Map<XClass, InheritanceState> inheritanceStatePerClass, Map<XClass, InheritanceState> inheritanceStatePerClass,
XProperty property, XProperty property,
ColumnsBuilder columnsBuilder, ColumnsBuilder columnsBuilder,
AnnotatedColumn[] columns, AnnotatedColumns columns,
XClass returnedClass, XClass returnedClass,
PropertyBinder propertyBinder) { PropertyBinder propertyBinder) {
// overrides from @MapsId or @IdClass if needed // overrides from @MapsId or @IdClass if needed
final boolean isComposite; final boolean isComposite;
final boolean isOverridden; final boolean isOverridden;
final AnnotatedColumn[] actualColumns; final AnnotatedColumns actualColumns;
if ( propertyBinder.isId() || propertyHolder.isOrWithinEmbeddedId() || propertyHolder.isInIdClass() ) { if ( propertyBinder.isId() || propertyHolder.isOrWithinEmbeddedId() || propertyHolder.isInIdClass() ) {
// the associated entity could be using an @IdClass making the overridden property a component // the associated entity could be using an @IdClass making the overridden property a component
final PropertyData overridingProperty = getPropertyOverriddenByMapperOrMapsId( final PropertyData overridingProperty = getPropertyOverriddenByMapperOrMapsId(
@ -1450,7 +1450,7 @@ private static void createBasicBinder(
Nullability nullability, Nullability nullability,
MetadataBuildingContext context, MetadataBuildingContext context,
XProperty property, XProperty property,
AnnotatedColumn[] columns, AnnotatedColumns columns,
PropertyBinder propertyBinder, PropertyBinder propertyBinder,
boolean isOverridden) { boolean isOverridden) {
//provide the basic property mapping //provide the basic property mapping
@ -1469,12 +1469,12 @@ private static void createBasicBinder(
//implicit type will check basic types and Serializable classes //implicit type will check basic types and Serializable classes
if ( propertyBinder.isId() || !optional && nullability != Nullability.FORCED_NULL ) { if ( propertyBinder.isId() || !optional && nullability != Nullability.FORCED_NULL ) {
//force columns to not null //force columns to not null
for ( AnnotatedColumn col : columns ) { for ( AnnotatedColumn column : columns.getColumns() ) {
if ( propertyBinder.isId() && col.isFormula() ) { if ( propertyBinder.isId() && column.isFormula() ) {
throw new CannotForceNonNullableException( "Identifier property '" throw new CannotForceNonNullableException( "Identifier property '"
+ getPath( propertyHolder, inferrredData ) + "' cannot map to a '@Formula'" ); + getPath( propertyHolder, inferrredData ) + "' cannot map to a '@Formula'" );
} }
col.forceNotNull(); column.forceNotNull();
} }
} }
@ -1499,7 +1499,7 @@ private static PropertyBinder createCompositeBinder(
MetadataBuildingContext context, MetadataBuildingContext context,
Map<XClass, InheritanceState> inheritanceStatePerClass, Map<XClass, InheritanceState> inheritanceStatePerClass,
XProperty property, XProperty property,
AnnotatedColumn[] columns, AnnotatedColumns columns,
XClass returnedClass, XClass returnedClass,
PropertyBinder propertyBinder, PropertyBinder propertyBinder,
boolean isOverridden, boolean isOverridden,
@ -1509,7 +1509,7 @@ private static PropertyBinder createCompositeBinder(
final AnnotatedJoinColumns actualColumns; final AnnotatedJoinColumns actualColumns;
if ( isOverridden ) { if ( isOverridden ) {
// careful: not always a @MapsId property, sometimes it's from an @IdClass // careful: not always a @MapsId property, sometimes it's from an @IdClass
PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId( final PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId(
propertyBinder.isId(), propertyHolder, property.getName(), context propertyBinder.isId(), propertyHolder, property.getName(), context
); );
referencedEntityName = mapsIdProperty.getClassOrElementName(); referencedEntityName = mapsIdProperty.getClassOrElementName();
@ -1518,7 +1518,7 @@ private static PropertyBinder createCompositeBinder(
joinColumns.setBuildingContext( context ); joinColumns.setBuildingContext( context );
joinColumns.setPropertyHolder( propertyHolder ); joinColumns.setPropertyHolder( propertyHolder );
joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns ); joinColumns.setColumns( (AnnotatedJoinColumn[]) columns.getColumns() );
actualColumns = joinColumns; actualColumns = joinColumns;
} }
else { else {
@ -1574,9 +1574,9 @@ private static void bindAny(
); );
} }
Cascade hibernateCascade = property.getAnnotation( Cascade.class ); final Cascade hibernateCascade = property.getAnnotation( Cascade.class );
OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class ); final OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
JoinTable assocTable = propertyHolder.getJoinTable(property); final JoinTable assocTable = propertyHolder.getJoinTable(property);
if ( assocTable != null ) { if ( assocTable != null ) {
Join join = propertyHolder.addJoin( assocTable, false ); Join join = propertyHolder.addJoin( assocTable, false );
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) {
@ -1600,7 +1600,7 @@ private static void bindAny(
private static void addIndexes( private static void addIndexes(
boolean inSecondPass, boolean inSecondPass,
XProperty property, XProperty property,
AnnotatedColumn[] columns, AnnotatedColumns columns,
AnnotatedJoinColumns joinColumns) { AnnotatedJoinColumns joinColumns) {
//process indexes after everything: in second pass, many to one has to be done before indexes //process indexes after everything: in second pass, many to one has to be done before indexes
final Index index = property.getAnnotation( Index.class ); final Index index = property.getAnnotation( Index.class );
@ -1613,7 +1613,7 @@ private static void addIndexes(
} }
else { else {
if ( columns != null ) { if ( columns != null ) {
for ( AnnotatedColumn column : columns ) { for ( AnnotatedColumn column : columns.getColumns() ) {
column.addIndex( index, inSecondPass ); column.addIndex( index, inSecondPass );
} }
} }
@ -1624,7 +1624,7 @@ private static void addIndexes(
private static void addNaturalIds( private static void addNaturalIds(
boolean inSecondPass, boolean inSecondPass,
XProperty property, XProperty property,
AnnotatedColumn[] columns, AnnotatedColumns columns,
AnnotatedJoinColumns joinColumns) { AnnotatedJoinColumns joinColumns) {
// Natural ID columns must reside in one single UniqueKey within the Table. // Natural ID columns must reside in one single UniqueKey within the Table.
// For now, simply ensure consistent naming. // For now, simply ensure consistent naming.
@ -1639,7 +1639,7 @@ private static void addNaturalIds(
} }
} }
else { else {
for ( AnnotatedColumn column : columns) { for ( AnnotatedColumn column : columns.getColumns() ) {
String keyName = "UK_" + Constraint.hashedName( column.getTable().getName() + "_NaturalID" ); String keyName = "UK_" + Constraint.hashedName( column.getTable().getName() + "_NaturalID" );
column.addUniqueKey( keyName, inSecondPass ); column.addUniqueKey( keyName, inSecondPass );
} }
@ -2254,8 +2254,8 @@ private static void bindAny(
binder.setAccessType( inferredData.getDefaultAccess() ); binder.setAccessType( inferredData.getDefaultAccess() );
binder.setCascade( cascadeStrategy ); binder.setCascade( cascadeStrategy );
Property prop = binder.makeProperty(); Property prop = binder.makeProperty();
//composite FK columns are in the same table so its OK //composite FK columns are in the same table, so it's OK
propertyHolder.addProperty( prop, columns.getColumns(), inferredData.getDeclaringClass() ); propertyHolder.addProperty( prop, columns, inferredData.getDeclaringClass() );
} }
public static HashMap<String, IdentifierGeneratorDefinition> buildGenerators( public static HashMap<String, IdentifierGeneratorDefinition> buildGenerators(

View File

@ -1049,17 +1049,18 @@ public static Any buildAnyValue(
EntityBinder entityBinder, EntityBinder entityBinder,
boolean optional, boolean optional,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final XProperty xProperty = inferredData.getProperty(); final XProperty property = inferredData.getProperty();
final AnnotatedJoinColumn[] columns = keyColumns.getColumns();
final Any value = new Any( context, columns[0].getTable(), true ); final Any value = new Any( context, keyColumns.getTable(), true );
value.setLazy( lazy ); value.setLazy( lazy );
value.setCascadeDeleteEnabled( cascadeOnDelete ); value.setCascadeDeleteEnabled( cascadeOnDelete );
final BasicValueBinder discriminatorValueBinder = final BasicValueBinder discriminatorValueBinder =
new BasicValueBinder( BasicValueBinder.Kind.ANY_DISCRIMINATOR, context ); new BasicValueBinder( BasicValueBinder.Kind.ANY_DISCRIMINATOR, context );
final AnnotatedColumn[] discriminatorColumns = buildColumnOrFormulaFromAnnotation( // TODO: if there can be only one discriminator column,
// why are we making a whole array of them??
final AnnotatedColumns discriminatorColumns = buildColumnOrFormulaFromAnnotation(
discriminatorColumn, discriminatorColumn,
discriminatorFormula, discriminatorFormula,
null, null,
@ -1069,17 +1070,20 @@ public static Any buildAnyValue(
entityBinder.getSecondaryTables(), entityBinder.getSecondaryTables(),
context context
); );
assert discriminatorColumns.length == 1; assert discriminatorColumns.getColumns().length == 1;
discriminatorColumns[0].setTable( value.getTable() );
discriminatorColumns.setTable( value.getTable() );
discriminatorValueBinder.setColumns( discriminatorColumns ); discriminatorValueBinder.setColumns( discriminatorColumns );
discriminatorValueBinder.setReturnedClassName( inferredData.getTypeName() ); discriminatorValueBinder.setReturnedClassName( inferredData.getTypeName() );
discriminatorValueBinder.setType( xProperty, xProperty.getType(), null, null ); discriminatorValueBinder.setType( property, property.getType(), null, null );
final BasicValue discriminatorDescriptor = discriminatorValueBinder.make(); final BasicValue discriminatorDescriptor = discriminatorValueBinder.make();
value.setDiscriminator( discriminatorDescriptor ); value.setDiscriminator( discriminatorDescriptor );
discriminatorValueBinder.fillSimpleValue(); discriminatorValueBinder.fillSimpleValue();
discriminatorColumns[0].linkWithValue( discriminatorDescriptor ); // TODO: this is nasty
final AnnotatedColumn firstDiscriminatorColumn = discriminatorColumns.getColumns()[0];
firstDiscriminatorColumn.linkWithValue( discriminatorDescriptor );
final JavaType<?> discriminatorJavaType = discriminatorDescriptor final JavaType<?> discriminatorJavaType = discriminatorDescriptor
.resolve() .resolve()
@ -1095,26 +1099,23 @@ public static Any buildAnyValue(
); );
value.setDiscriminatorValueMappings( discriminatorValueMappings ); value.setDiscriminatorValueMappings( discriminatorValueMappings );
BasicValueBinder keyValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ANY_KEY, context ); final BasicValueBinder keyValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ANY_KEY, context );
final AnnotatedJoinColumn[] columns = keyColumns.getColumns();
assert columns.length == 1; assert columns.length == 1;
columns[0].setTable( value.getTable() ); keyColumns.setTable( value.getTable() );
keyValueBinder.setColumns(columns); keyValueBinder.setColumns( keyColumns );
if ( !optional ) { if ( !optional ) {
for ( AnnotatedJoinColumn column : columns ) { for ( AnnotatedJoinColumn column : columns ) {
column.setNullable( false ); column.setNullable( false );
} }
} }
keyValueBinder.setType( xProperty, xProperty.getType(), null, null ); keyValueBinder.setType( property, property.getType(), null, null );
final BasicValue keyDescriptor = keyValueBinder.make(); final BasicValue keyDescriptor = keyValueBinder.make();
value.setKey( keyDescriptor ); value.setKey( keyDescriptor );
keyValueBinder.fillSimpleValue(); keyValueBinder.fillSimpleValue();
AnnotatedColumn.checkPropertyConsistency( final String path = qualify( propertyHolder.getEntityName(), inferredData.getPropertyName() );
columns, AnnotatedColumn.checkPropertyConsistency( columns, path );
propertyHolder.getEntityName() + "." + inferredData.getPropertyName()
);
columns[0].linkWithValue( keyDescriptor ); columns[0].linkWithValue( keyDescriptor );
return value; return value;
} }

View File

@ -12,6 +12,7 @@
import jakarta.persistence.Converts; import jakarta.persistence.Converts;
import jakarta.persistence.JoinTable; import jakarta.persistence.JoinTable;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XClass;
@ -181,12 +182,23 @@ public String getEntityName() {
return persistentClass.getEntityName(); return persistentClass.getEntityName();
} }
public void addProperty(Property prop, AnnotatedColumn[] columns, XClass declaringClass) { public void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass) {
//Ejb3Column.checkPropertyConsistency( ); //already called earlier //Ejb3Column.checkPropertyConsistency( ); //already called earlier
if ( columns != null && columns[0].isSecondary() ) { if ( columns != null ) {
final AnnotatedColumn firstColumn = columns.getColumns()[0];
if ( firstColumn.isSecondary() ) {
//TODO move the getJoin() code here? //TODO move the getJoin() code here?
final Join join = columns[0].getJoin(); for ( AnnotatedColumn column : columns.getColumns() ) {
addPropertyToJoin( prop, declaringClass, join ); if ( !column.isSecondary() || column.getJoin() != firstColumn.getJoin() ) {
//TODO: fix the error message
throw new AnnotationException("different columns mapped to different tables for a single property");
}
}
addPropertyToJoin( prop, declaringClass, firstColumn.getJoin() );
}
else {
addProperty( prop, declaringClass );
}
} }
else { else {
addProperty( prop, declaringClass ); addProperty( prop, declaringClass );

View File

@ -309,7 +309,7 @@ public String getEntityName() {
return collection.getOwner().getEntityName(); return collection.getOwner().getEntityName();
} }
public void addProperty(Property prop, AnnotatedColumn[] columns, XClass declaringClass) { public void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass) {
//Ejb3Column.checkPropertyConsistency( ); //already called earlier //Ejb3Column.checkPropertyConsistency( ); //already called earlier
throw new AssertionFailure( "addProperty to a join table of a collection: does it make sense?" ); throw new AssertionFailure( "addProperty to a join table of a collection: does it make sense?" );
} }

View File

@ -52,7 +52,7 @@ class ColumnsBuilder {
private final PropertyData inferredData; private final PropertyData inferredData;
private final EntityBinder entityBinder; private final EntityBinder entityBinder;
private final MetadataBuildingContext buildingContext; private final MetadataBuildingContext buildingContext;
private AnnotatedColumn[] columns; private AnnotatedColumns columns;
private AnnotatedJoinColumns joinColumns; private AnnotatedJoinColumns joinColumns;
public ColumnsBuilder( public ColumnsBuilder(
@ -70,7 +70,7 @@ public ColumnsBuilder(
this.buildingContext = buildingContext; this.buildingContext = buildingContext;
} }
public AnnotatedColumn[] getColumns() { public AnnotatedColumns getColumns() {
return columns; return columns;
} }
@ -158,8 +158,8 @@ else if ( joinColumns == null && property.isAnnotationPresent( org.hibernate.ann
if ( nullability == Nullability.FORCED_NOT_NULL ) { if ( nullability == Nullability.FORCED_NOT_NULL ) {
//force columns to not null //force columns to not null
for (AnnotatedColumn col : columns ) { for ( AnnotatedColumn column : columns.getColumns() ) {
col.forceNotNull(); column.forceNotNull();
} }
} }
return this; return this;
@ -291,13 +291,9 @@ else if ( property.isAnnotationPresent( JoinColumns.class ) ) {
} }
} }
AnnotatedColumn[] overrideColumnFromMapperOrMapsIdProperty(boolean isId) { AnnotatedColumns overrideColumnFromMapperOrMapsIdProperty(boolean isId) {
final PropertyData overridingProperty = getPropertyOverriddenByMapperOrMapsId( final PropertyData overridingProperty =
isId, getPropertyOverriddenByMapperOrMapsId( isId, propertyHolder, property.getName(), buildingContext );
propertyHolder,
property.getName(),
buildingContext
);
return overridingProperty != null ? buildExplicitOrDefaultJoinColumn( overridingProperty ) : columns; return overridingProperty != null ? buildExplicitOrDefaultJoinColumn( overridingProperty ) : columns;
} }
@ -305,10 +301,10 @@ AnnotatedColumn[] overrideColumnFromMapperOrMapsIdProperty(boolean isId) {
* Useful to override a column either by {@code @MapsId} or by {@code @IdClass} * Useful to override a column either by {@code @MapsId} or by {@code @IdClass}
*/ */
//TODO: should we introduce an AnnotatedColumns type and return that here? //TODO: should we introduce an AnnotatedColumns type and return that here?
private AnnotatedColumn[] buildExplicitOrDefaultJoinColumn(PropertyData overridingProperty) { private AnnotatedColumns buildExplicitOrDefaultJoinColumn(PropertyData overridingProperty) {
final AnnotatedJoinColumns columns = buildExplicitJoinColumns( overridingProperty.getProperty(), overridingProperty ); final AnnotatedJoinColumns columns = buildExplicitJoinColumns( overridingProperty.getProperty(), overridingProperty );
return columns == null return columns == null
? buildDefaultJoinColumnsForToOne( overridingProperty.getProperty(), overridingProperty ).getColumns() ? buildDefaultJoinColumnsForToOne( overridingProperty.getProperty(), overridingProperty )
: columns.getColumns(); : columns;
} }
} }

View File

@ -251,12 +251,12 @@ protected AttributeConversionInfo locateAttributeConversionInfo(XProperty proper
@Override @Override
protected AttributeConversionInfo locateAttributeConversionInfo(String path) { protected AttributeConversionInfo locateAttributeConversionInfo(String path) {
final String embeddedPath = StringHelper.qualifyConditionally( embeddedAttributeName, path ); final String embeddedPath = StringHelper.qualifyConditionally( embeddedAttributeName, path );
AttributeConversionInfo fromParent = parent.locateAttributeConversionInfo( embeddedPath ); final AttributeConversionInfo fromParent = parent.locateAttributeConversionInfo( embeddedPath );
if ( fromParent != null ) { if ( fromParent != null ) {
return fromParent; return fromParent;
} }
AttributeConversionInfo fromEmbedded = attributeConversionInfoMap.get( embeddedPath ); final AttributeConversionInfo fromEmbedded = attributeConversionInfoMap.get( embeddedPath );
if ( fromEmbedded != null ) { if ( fromEmbedded != null ) {
return fromEmbedded; return fromEmbedded;
} }
@ -268,13 +268,13 @@ public String getEntityName() {
return component.getComponentClassName(); return component.getComponentClassName();
} }
public void addProperty(Property prop, AnnotatedColumn[] columns, XClass declaringClass) { public void addProperty(Property property, AnnotatedColumns columns, XClass declaringClass) {
//Ejb3Column.checkPropertyConsistency( ); //already called earlier //Ejb3Column.checkPropertyConsistency( ); //already called earlier
// Check table matches between the component and the columns // Check table matches between the component and the columns
// if not, change the component table if no properties are set // if not, change the component table if no properties are set
// if a property is set already the core cannot support that // if a property is set already the core cannot support that
if ( columns != null ) { if ( columns != null ) {
Table table = columns[0].getTable(); final Table table = columns.getTable();
if ( !table.equals( component.getTable() ) ) { if ( !table.equals( component.getTable() ) ) {
if ( component.getPropertySpan() == 0 ) { if ( component.getPropertySpan() == 0 ) {
component.setTable( table ); component.setTable( table );
@ -288,12 +288,11 @@ public void addProperty(Property prop, AnnotatedColumn[] columns, XClass declari
} }
} }
} }
addProperty( prop, declaringClass ); addProperty( property, declaringClass );
} }
public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) { public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) {
return parent.addJoin( joinTableAnn, noDelayInPkColumnCreation ); return parent.addJoin( joinTableAnn, noDelayInPkColumnCreation );
} }
public String getClassName() { public String getClassName() {

View File

@ -59,16 +59,15 @@ public IndexOrUniqueKeySecondPass(String indexName, AnnotatedColumn column, Meta
@Override @Override
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException { public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
if ( columns != null ) { if ( columns != null ) {
for ( String column1 : columns ) { for ( String columnName : columns ) {
addConstraintToColumn( column1 ); addConstraintToColumn( columnName );
} }
} }
if ( column != null ) { if ( column != null ) {
this.table = column.getTable(); table = column.getTable();
final PropertyHolder propertyHolder = column.getPropertyHolder(); final PropertyHolder propertyHolder = column.getPropertyHolder();
final String entityName = ( propertyHolder.isComponent() ) ?
String entityName = ( propertyHolder.isComponent() ) ?
propertyHolder.getPersistentClass().getEntityName() : propertyHolder.getPersistentClass().getEntityName() :
propertyHolder.getEntityName(); propertyHolder.getEntityName();
@ -77,8 +76,7 @@ public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws
if ( property.getValue() instanceof Component ) { if ( property.getValue() instanceof Component ) {
final Component component = (Component) property.getValue(); final Component component = (Component) property.getValue();
final List<Column> columns = new ArrayList<>();
List<Column> columns = new ArrayList<>();
for ( Selectable selectable: component.getSelectables() ) { for ( Selectable selectable: component.getSelectables() ) {
if ( selectable instanceof Column ) { if ( selectable instanceof Column ) {
columns.add( (Column) selectable ); columns.add( (Column) selectable );
@ -97,9 +95,7 @@ public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws
private void addConstraintToColumn(final String columnName ) { private void addConstraintToColumn(final String columnName ) {
Column column = table.getColumn( Column column = table.getColumn(
new Column( new Column( buildingContext.getMetadataCollector().getPhysicalColumnName( table, columnName ) )
buildingContext.getMetadataCollector().getPhysicalColumnName( table, columnName )
)
); );
if ( column == null ) { if ( column == null ) {
throw new AnnotationException( throw new AnnotationException(
@ -117,13 +113,13 @@ private void addConstraintToColumn(final String columnName ) {
private void addConstraintToColumns(List<Column> columns) { private void addConstraintToColumns(List<Column> columns) {
if ( unique ) { if ( unique ) {
UniqueKey uniqueKey = table.getOrCreateUniqueKey( indexName ); final UniqueKey uniqueKey = table.getOrCreateUniqueKey( indexName );
for ( Column column : columns ) { for ( Column column : columns ) {
uniqueKey.addColumn( column ); uniqueKey.addColumn( column );
} }
} }
else { else {
Index index = table.getOrCreateIndex( indexName ); final Index index = table.getOrCreateIndex( indexName );
for ( Column column : columns ) { for ( Column column : columns ) {
index.addColumn( column ); index.addColumn( column );
} }

View File

@ -35,7 +35,7 @@ public interface PropertyHolder {
void addProperty(Property prop, XClass declaringClass); void addProperty(Property prop, XClass declaringClass);
void addProperty(Property prop, AnnotatedColumn[] columns, XClass declaringClass); void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass);
KeyValue getIdentifier(); KeyValue getIdentifier();

View File

@ -142,7 +142,7 @@ private static void bindManyToOne(
MetadataBuildingContext context) { MetadataBuildingContext context) {
// All FK columns should be in the same table // All FK columns should be in the same table
final org.hibernate.mapping.ManyToOne value = final org.hibernate.mapping.ManyToOne value =
new org.hibernate.mapping.ManyToOne( context, joinColumns.getColumns()[0].getTable() ); new org.hibernate.mapping.ManyToOne( context, joinColumns.getTable() );
if ( unique ) { if ( unique ) {
// This is a @OneToOne mapped to a physical o.h.mapping.ManyToOne // This is a @OneToOne mapped to a physical o.h.mapping.ManyToOne
value.markAsLogicalOneToOne(); value.markAsLogicalOneToOne();
@ -269,7 +269,7 @@ else if (hasSpecjManyToOne) {
propertyBinder.setInsertable( firstColumn.isInsertable() ); propertyBinder.setInsertable( firstColumn.isInsertable() );
propertyBinder.setUpdatable( firstColumn.isUpdatable() ); propertyBinder.setUpdatable( firstColumn.isUpdatable() );
} }
propertyBinder.setColumns( columns.getColumns() ); propertyBinder.setColumns( columns );
propertyBinder.setAccessType( inferredData.getDefaultAccess() ); propertyBinder.setAccessType( inferredData.getDefaultAccess() );
propertyBinder.setCascade( cascadeStrategy ); propertyBinder.setCascade( cascadeStrategy );
propertyBinder.setProperty( property ); propertyBinder.setProperty( property );

View File

@ -55,6 +55,7 @@
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedColumn; import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.AnnotatedJoinColumn; import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.AnnotatedJoinColumns; import org.hibernate.cfg.AnnotatedJoinColumns;
import org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass; import org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass;
@ -153,7 +154,7 @@ public enum Kind {
private TimeZoneStorageType timeZoneStorageType; private TimeZoneStorageType timeZoneStorageType;
private Table table; private Table table;
private AnnotatedColumn[] columns; private AnnotatedColumns columns;
private BasicValue basicValue; private BasicValue basicValue;
@ -274,7 +275,7 @@ public void setTable(Table table) {
this.table = table; this.table = table;
} }
public void setColumns(AnnotatedColumn[] columns) { public void setColumns(AnnotatedColumns columns) {
this.columns = columns; this.columns = columns;
} }
@ -1070,7 +1071,7 @@ public void setExplicitType(String explicitType) {
} }
private void validate() { private void validate() {
AnnotatedColumn.checkPropertyConsistency( columns, propertyName ); AnnotatedColumn.checkPropertyConsistency( columns.getColumns(), propertyName );
} }
public BasicValue make() { public BasicValue make() {
@ -1083,7 +1084,7 @@ public BasicValue make() {
LOG.debugf( "building BasicValue for %s", propertyName ); LOG.debugf( "building BasicValue for %s", propertyName );
if ( table == null ) { if ( table == null ) {
table = columns[0].getTable(); table = columns.getTable();
} }
basicValue = new BasicValue( buildingContext, table ); basicValue = new BasicValue( buildingContext, table );
@ -1125,18 +1126,19 @@ public BasicValue make() {
public void linkWithValue() { public void linkWithValue() {
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector(); final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
if ( !collector.isInSecondPass() && columns[0].isNameDeferred() && referencedEntityName != null ) { final AnnotatedColumn firstColumn = columns.getColumns()[0];
if ( !collector.isInSecondPass() && firstColumn.isNameDeferred() && referencedEntityName != null ) {
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns(); final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
joinColumns.setBuildingContext( buildingContext ); joinColumns.setBuildingContext( buildingContext );
joinColumns.setPropertyHolder( columns[0].getPropertyHolder() ); joinColumns.setPropertyHolder( firstColumn.getPropertyHolder() );
joinColumns.setPropertyName( columns[0].getPropertyName() ); joinColumns.setPropertyName( firstColumn.getPropertyName() );
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns ); joinColumns.setColumns( (AnnotatedJoinColumn[]) columns.getColumns() );
collector.addSecondPass( collector.addSecondPass(
new PkDrivenByDefaultMapsIdSecondPass( referencedEntityName, joinColumns, basicValue ) new PkDrivenByDefaultMapsIdSecondPass( referencedEntityName, joinColumns, basicValue )
); );
} }
else { else {
for ( AnnotatedColumn column : columns ) { for ( AnnotatedColumn column : columns.getColumns() ) {
column.linkWithValue( basicValue ); column.linkWithValue( basicValue );
} }
} }

View File

@ -100,6 +100,7 @@
import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedClassType; import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AnnotatedColumn; import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.AnnotatedJoinColumn; import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.AnnotatedJoinColumns; import org.hibernate.cfg.AnnotatedJoinColumns;
import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.AnnotationBinder;
@ -173,6 +174,7 @@
import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.StringHelper.nullIfEmpty; import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
import static org.hibernate.internal.util.StringHelper.qualify; import static org.hibernate.internal.util.StringHelper.qualify;
import static org.hibernate.internal.util.collections.ArrayHelper.isEmpty;
/** /**
* Base class for binding different types of collections to Hibernate configuration objects. * Base class for binding different types of collections to Hibernate configuration objects.
@ -216,12 +218,12 @@ public abstract class CollectionBinder {
protected AnnotatedJoinColumns foreignJoinColumns; protected AnnotatedJoinColumns foreignJoinColumns;
private AnnotatedJoinColumns joinColumns; private AnnotatedJoinColumns joinColumns;
private boolean isExplicitAssociationTable; private boolean isExplicitAssociationTable;
private AnnotatedColumn[] elementColumns; private AnnotatedColumns elementColumns;
protected boolean isEmbedded; protected boolean isEmbedded;
protected XProperty property; protected XProperty property;
protected NotFoundAction notFoundAction; protected NotFoundAction notFoundAction;
private TableBinder tableBinder; private TableBinder tableBinder;
protected AnnotatedColumn[] mapKeyColumns; protected AnnotatedColumns mapKeyColumns;
protected AnnotatedJoinColumns mapKeyManyToManyColumns; protected AnnotatedJoinColumns mapKeyManyToManyColumns;
protected Map<String, IdentifierGeneratorDefinition> localGenerators; protected Map<String, IdentifierGeneratorDefinition> localGenerators;
protected Map<XClass, InheritanceState> inheritanceStatePerClass; protected Map<XClass, InheritanceState> inheritanceStatePerClass;
@ -321,7 +323,7 @@ && isToManyAssociationWithinEmbeddableCollection( propertyHolder ) ) {
? inferredData ? inferredData
: new WrappedInferredData( inferredData, "element" ); : new WrappedInferredData( inferredData, "element" );
final Comment comment = property.getAnnotation( Comment.class ); final Comment comment = property.getAnnotation( Comment.class );
final AnnotatedColumn[] elementColumns = elementColumns( final AnnotatedColumns elementColumns = elementColumns(
propertyHolder, propertyHolder,
nullability, nullability,
entityBinder, entityBinder,
@ -419,6 +421,7 @@ private static String handleTargetEntity(
if ( oneToManyAnn != null ) { if ( oneToManyAnn != null ) {
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) {
if ( column.isSecondary() ) { if ( column.isSecondary() ) {
//TODO: fix the error message
throw new NotYetImplementedException( "Collections having FK in secondary table" ); throw new NotYetImplementedException( "Collections having FK in secondary table" );
} }
} }
@ -434,6 +437,7 @@ private static String handleTargetEntity(
else if ( elementCollectionAnn != null ) { else if ( elementCollectionAnn != null ) {
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) {
if ( column.isSecondary() ) { if ( column.isSecondary() ) {
//TODO: fix the error message
throw new NotYetImplementedException( "Collections having FK in secondary table" ); throw new NotYetImplementedException( "Collections having FK in secondary table" );
} }
} }
@ -487,7 +491,7 @@ private static boolean isToManyAssociationWithinEmbeddableCollection(PropertyHol
} }
} }
private static AnnotatedColumn[] elementColumns( private static AnnotatedColumns elementColumns(
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
Nullability nullability, Nullability nullability,
EntityBinder entityBinder, EntityBinder entityBinder,
@ -553,7 +557,7 @@ private static JoinColumn[] mapKeyColumns(
? new jakarta.persistence.Column[] { new MapKeyColumnDelegator( property.getAnnotation( MapKeyColumn.class ) ) } ? new jakarta.persistence.Column[] { new MapKeyColumnDelegator( property.getAnnotation( MapKeyColumn.class ) ) }
: null; : null;
final AnnotatedColumn[] mapColumns = buildColumnsFromAnnotations( final AnnotatedColumns mapColumns = buildColumnsFromAnnotations(
keyColumns, keyColumns,
comment, comment,
Nullability.FORCED_NOT_NULL, Nullability.FORCED_NOT_NULL,
@ -1544,9 +1548,8 @@ protected void bindOneToManySecondPass(Map<String, PersistentClass> persistentCl
foreignJoinColumns.setPersistentClass( associatedClass, joins, inheritanceStatePerClass ); foreignJoinColumns.setPersistentClass( associatedClass, joins, inheritanceStatePerClass );
for ( AnnotatedJoinColumn column : foreignJoinColumns.getColumns() ) { for ( AnnotatedJoinColumn column : foreignJoinColumns.getColumns() ) {
column.setJoins( joins ); column.setJoins( joins );
//TODO: this is lame, should get the table from foreignJoinColumns
collection.setCollectionTable( column.getTable() );
} }
collection.setCollectionTable( foreignJoinColumns.getTable() );
if ( LOG.isDebugEnabled() ) { if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Mapping collection: %s -> %s", collection.getRole(), collection.getCollectionTable().getName() ); LOG.debugf( "Mapping collection: %s -> %s", collection.getRole(), collection.getCollectionTable().getName() );
} }
@ -1555,7 +1558,7 @@ protected void bindOneToManySecondPass(Map<String, PersistentClass> persistentCl
handleWhere( false ); handleWhere( false );
final PersistentClass targetEntity = persistentClasses.get( getElementType().getName() ); final PersistentClass targetEntity = persistentClasses.get( getElementType().getName() );
bindCollectionSecondPass( targetEntity, foreignJoinColumns, cascadeDeleteEnabled, buildingContext ); bindCollectionSecondPass( targetEntity, foreignJoinColumns, cascadeDeleteEnabled );
if ( !collection.isInverse() && !collection.getKey().isNullable() ) { if ( !collection.isInverse() && !collection.getKey().isNullable() ) {
createOneToManyBackref( oneToMany ); createOneToManyBackref( oneToMany );
@ -1838,12 +1841,11 @@ private DependantValue buildCollectionKey(
boolean cascadeDeleteEnabled, boolean cascadeDeleteEnabled,
boolean noConstraintByDefault, boolean noConstraintByDefault,
XProperty property, XProperty property,
PropertyHolder propertyHolder, PropertyHolder propertyHolder) {
MetadataBuildingContext buildingContext) {
// give a chance to override the referenced property name // give a chance to override the referenced property name
// has to do that here because the referencedProperty creation happens in a FKSecondPass for ManyToOne yuk! // has to do that here because the referencedProperty creation happens in a FKSecondPass for ManyToOne yuk!
overrideReferencedPropertyName( collection, joinColumns, buildingContext ); overrideReferencedPropertyName( collection, joinColumns );
final String referencedPropertyName = collection.getReferencedPropertyName(); final String referencedPropertyName = collection.getReferencedPropertyName();
//binding key reference using column //binding key reference using column
@ -1955,15 +1957,12 @@ private static void handleForeignKeyConstraint(boolean noConstraintByDefault, De
} }
} }
private void overrideReferencedPropertyName( private void overrideReferencedPropertyName(Collection collection, AnnotatedJoinColumns joinColumns) {
Collection collection,
AnnotatedJoinColumns joinColumns,
MetadataBuildingContext context) {
if ( hasMappedBy() && joinColumns.getColumns().length > 0 ) { if ( hasMappedBy() && joinColumns.getColumns().length > 0 ) {
final String entityName = joinColumns.getManyToManyOwnerSideEntityName() != null final String entityName = joinColumns.getManyToManyOwnerSideEntityName() != null
? "inverse__" + joinColumns.getManyToManyOwnerSideEntityName() ? "inverse__" + joinColumns.getManyToManyOwnerSideEntityName()
: joinColumns.getPropertyHolder().getEntityName(); : joinColumns.getPropertyHolder().getEntityName();
final InFlightMetadataCollector collector = context.getMetadataCollector(); final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
final String referencedProperty = collector.getPropertyReferencedAssociation( entityName, mappedBy ); final String referencedProperty = collector.getPropertyReferencedAssociation( entityName, mappedBy );
if ( referencedProperty != null ) { if ( referencedProperty != null ) {
collection.setReferencedPropertyName( referencedProperty ); collection.setReferencedPropertyName( referencedProperty );
@ -2021,7 +2020,7 @@ private void bindManyToManySecondPass(Map<String, PersistentClass> persistentCla
bindFilters( isCollectionOfEntities ); bindFilters( isCollectionOfEntities );
handleWhere( isCollectionOfEntities ); handleWhere( isCollectionOfEntities );
bindCollectionSecondPass( targetEntity, joinColumns, cascadeDeleteEnabled, buildingContext ); bindCollectionSecondPass( targetEntity, joinColumns, cascadeDeleteEnabled );
if ( isCollectionOfEntities ) { if ( isCollectionOfEntities ) {
final ManyToOne element = handleCollectionOfEntities( final ManyToOne element = handleCollectionOfEntities(
@ -2033,7 +2032,7 @@ private void bindManyToManySecondPass(Map<String, PersistentClass> persistentCla
targetEntity, targetEntity,
hqlOrderBy hqlOrderBy
); );
bindManyToManyInverseForeignKey( targetEntity, inverseJoinColumns, element, oneToMany, buildingContext ); bindManyToManyInverseForeignKey( targetEntity, inverseJoinColumns, element, oneToMany );
} }
else if ( isManyToAny ) { else if ( isManyToAny ) {
handleManyToAny( handleManyToAny(
@ -2052,7 +2051,6 @@ else if ( isManyToAny ) {
elementType, elementType,
property, property,
propertyHolder, propertyHolder,
buildingContext,
hqlOrderBy hqlOrderBy
); );
} }
@ -2062,12 +2060,11 @@ else if ( isManyToAny ) {
private void handleElementCollection( private void handleElementCollection(
Collection collection, Collection collection,
AnnotatedColumn[] elementColumns, AnnotatedColumns elementColumns,
boolean isEmbedded, boolean isEmbedded,
XClass elementType, XClass elementType,
XProperty property, XProperty property,
PropertyHolder parentPropertyHolder, PropertyHolder parentPropertyHolder,
MetadataBuildingContext buildingContext,
String hqlOrderBy) { String hqlOrderBy) {
final XClass elementClass; final XClass elementClass;
final AnnotatedClassType classType; final AnnotatedClassType classType;
@ -2172,24 +2169,14 @@ else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().get
final BasicValueBinder elementBinder = final BasicValueBinder elementBinder =
new BasicValueBinder( BasicValueBinder.Kind.COLLECTION_ELEMENT, buildingContext ); new BasicValueBinder( BasicValueBinder.Kind.COLLECTION_ELEMENT, buildingContext );
elementBinder.setReturnedClassName( elementType.getName() ); elementBinder.setReturnedClassName( elementType.getName() );
if ( elementColumns == null || elementColumns.length == 0 ) { final AnnotatedColumns actualColumns = createElementColumnsIfNecessary(
elementColumns = new AnnotatedColumn[1]; collection,
AnnotatedColumn column = new AnnotatedColumn(); elementColumns,
column.setImplicit( false ); Collection.DEFAULT_ELEMENT_COLUMN_NAME,
//not following the spec but more clean null,
column.setNullable( true ); buildingContext
column.setLogicalColumnName( Collection.DEFAULT_ELEMENT_COLUMN_NAME ); );
//TODO create an EMPTY_JOINS collection elementBinder.setColumns( actualColumns );
column.setJoins( new HashMap<>() );
column.setBuildingContext(buildingContext);
column.bind();
elementColumns[0] = column;
}
//override the table
for (AnnotatedColumn column : elementColumns) {
column.setTable( collection.getCollectionTable() );
}
elementBinder.setColumns(elementColumns);
elementBinder.setType( elementBinder.setType(
property, property,
elementClass, elementClass,
@ -2206,6 +2193,34 @@ else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().get
} }
} }
static AnnotatedColumns createElementColumnsIfNecessary(
Collection collection,
AnnotatedColumns elementColumns,
String defaultName,
Long defaultLength,
MetadataBuildingContext context) {
if ( elementColumns == null || isEmpty( elementColumns.getColumns() ) ) {
final AnnotatedColumn column = new AnnotatedColumn();
column.setLogicalColumnName( defaultName );
if ( defaultLength!=null ) {
column.setLength( defaultLength );
}
column.setImplicit( false );
//not following the spec but more clean
column.setNullable( true );
//TODO create an EMPTY_JOINS collection
column.setJoins( new HashMap<>() );
column.setBuildingContext( context );
column.bind();
final AnnotatedColumns result = new AnnotatedColumns();
result.setColumns( new AnnotatedColumn[] { column } );
elementColumns = result;
}
//override the table
elementColumns.setTable( collection.getCollectionTable() );
return elementColumns;
}
private ManyToOne handleCollectionOfEntities( private ManyToOne handleCollectionOfEntities(
Collection collection, Collection collection,
XClass elementType, XClass elementType,
@ -2214,7 +2229,7 @@ private ManyToOne handleCollectionOfEntities(
MetadataBuildingContext buildingContext, MetadataBuildingContext buildingContext,
PersistentClass collectionEntity, PersistentClass collectionEntity,
String hqlOrderBy) { String hqlOrderBy) {
ManyToOne element = new ManyToOne( buildingContext, collection.getCollectionTable() ); final ManyToOne element = new ManyToOne( buildingContext, collection.getCollectionTable() );
collection.setElement( element ); collection.setElement( element );
element.setReferencedEntityName( elementType.getName() ); element.setReferencedEntityName( elementType.getName() );
//element.setFetchMode( fetchMode ); //element.setFetchMode( fetchMode );
@ -2273,16 +2288,14 @@ private void handleManyToAny(
buildingContext.getBootstrapContext().getReflectionManager() buildingContext.getBootstrapContext().getReflectionManager()
); );
XProperty prop = inferredData.getProperty(); final XProperty prop = inferredData.getProperty();
final jakarta.persistence.Column discriminatorColumnAnn = prop.getAnnotation( jakarta.persistence.Column.class ); final jakarta.persistence.Column discriminatorColumnAnn = prop.getAnnotation( jakarta.persistence.Column.class );
final Formula discriminatorFormulaAnn = getOverridableAnnotation( prop, Formula.class, buildingContext); final Formula discriminatorFormulaAnn = getOverridableAnnotation( prop, Formula.class, buildingContext);
//override the table //override the table
for ( AnnotatedColumn column : inverseJoinColumns.getColumns() ) { inverseJoinColumns.setTable( collection.getCollectionTable() );
column.setTable( collection.getCollectionTable() );
}
ManyToAny anyAnn = property.getAnnotation( ManyToAny.class ); final ManyToAny anyAnn = property.getAnnotation( ManyToAny.class );
final Any any = buildAnyValue( final Any any = buildAnyValue(
discriminatorColumnAnn, discriminatorColumnAnn,
discriminatorFormulaAnn, discriminatorFormulaAnn,
@ -2486,8 +2499,7 @@ private static void checkFilterConditions(Collection collection) {
private void bindCollectionSecondPass( private void bindCollectionSecondPass(
PersistentClass targetEntity, PersistentClass targetEntity,
AnnotatedJoinColumns joinColumns, AnnotatedJoinColumns joinColumns,
boolean cascadeDeleteEnabled, boolean cascadeDeleteEnabled) {
MetadataBuildingContext context) {
if ( !hasMappedBy() ) { if ( !hasMappedBy() ) {
createSyntheticPropertyReference( createSyntheticPropertyReference(
@ -2497,7 +2509,7 @@ private void bindCollectionSecondPass(
collection, collection,
propertyName, propertyName,
false, false,
context buildingContext
); );
} }
@ -2505,10 +2517,9 @@ private void bindCollectionSecondPass(
collection, collection,
joinColumns, joinColumns,
cascadeDeleteEnabled, cascadeDeleteEnabled,
context.getBuildingOptions().isNoConstraintByDefault(), buildingContext.getBuildingOptions().isNoConstraintByDefault(),
property, property,
propertyHolder, propertyHolder
context
); );
if ( property.isAnnotationPresent( ElementCollection.class ) ) { if ( property.isAnnotationPresent( ElementCollection.class ) ) {
@ -2521,7 +2532,7 @@ private void bindCollectionSecondPass(
joinColumns, joinColumns,
key, key,
false, false,
context buildingContext
); );
key.sortProperties(); key.sortProperties();
} }
@ -2545,8 +2556,7 @@ public void bindManyToManyInverseForeignKey(
PersistentClass targetEntity, PersistentClass targetEntity,
AnnotatedJoinColumns joinColumns, AnnotatedJoinColumns joinColumns,
SimpleValue value, SimpleValue value,
boolean unique, boolean unique) {
MetadataBuildingContext context) {
if ( hasMappedBy() ) { if ( hasMappedBy() ) {
final Property property = targetEntity.getRecursiveProperty( mappedBy ); final Property property = targetEntity.getRecursiveProperty( mappedBy );
final List<Selectable> mappedByColumns = mappedByColumns( targetEntity, property ); final List<Selectable> mappedByColumns = mappedByColumns( targetEntity, property );
@ -2554,12 +2564,12 @@ public void bindManyToManyInverseForeignKey(
for ( Selectable selectable: mappedByColumns ) { for ( Selectable selectable: mappedByColumns ) {
firstColumn.linkValueUsingAColumnCopy( (Column) selectable, value ); firstColumn.linkValueUsingAColumnCopy( (Column) selectable, value );
} }
final String referencedPropertyName = context.getMetadataCollector() final String referencedPropertyName = buildingContext.getMetadataCollector()
.getPropertyReferencedAssociation( targetEntity.getEntityName(), mappedBy ); .getPropertyReferencedAssociation( targetEntity.getEntityName(), mappedBy );
if ( referencedPropertyName != null ) { if ( referencedPropertyName != null ) {
//TODO always a many to one? //TODO always a many to one?
( (ManyToOne) value ).setReferencedPropertyName( referencedPropertyName ); ( (ManyToOne) value ).setReferencedPropertyName( referencedPropertyName );
context.getMetadataCollector() buildingContext.getMetadataCollector()
.addUniquePropertyReference( targetEntity.getEntityName(), referencedPropertyName ); .addUniquePropertyReference( targetEntity.getEntityName(), referencedPropertyName );
} }
( (ManyToOne) value ).setReferenceToPrimaryKey( referencedPropertyName == null ); ( (ManyToOne) value ).setReferenceToPrimaryKey( referencedPropertyName == null );
@ -2573,7 +2583,7 @@ public void bindManyToManyInverseForeignKey(
value, value,
propertyName, propertyName,
true, true,
context buildingContext
); );
if ( notFoundAction == NotFoundAction.IGNORE ) { if ( notFoundAction == NotFoundAction.IGNORE ) {
value.disableForeignKey(); value.disableForeignKey();
@ -2584,7 +2594,7 @@ public void bindManyToManyInverseForeignKey(
joinColumns, joinColumns,
value, value,
unique, unique,
context buildingContext
); );
} }
} }
@ -2617,7 +2627,7 @@ public void setExplicitAssociationTable(boolean explicitAssocTable) {
this.isExplicitAssociationTable = explicitAssocTable; this.isExplicitAssociationTable = explicitAssocTable;
} }
public void setElementColumns(AnnotatedColumn[] elementColumns) { public void setElementColumns(AnnotatedColumns elementColumns) {
this.elementColumns = elementColumns; this.elementColumns = elementColumns;
} }
@ -2637,7 +2647,7 @@ public void setNotFoundAction(NotFoundAction notFoundAction) {
this.notFoundAction = notFoundAction; this.notFoundAction = notFoundAction;
} }
public void setMapKeyColumns(AnnotatedColumn[] mapKeyColumns) { public void setMapKeyColumns(AnnotatedColumns mapKeyColumns) {
this.mapKeyColumns = mapKeyColumns; this.mapKeyColumns = mapKeyColumns;
} }

View File

@ -789,7 +789,7 @@ private static void bindDiscriminatorColumnToRootPersistentClass(
} }
discriminatorColumn.setJoins( secondaryTables ); discriminatorColumn.setJoins( secondaryTables );
discriminatorColumn.setPropertyHolder( propertyHolder ); discriminatorColumn.setPropertyHolder( propertyHolder );
BasicValue discriminatorColumnBinding = new BasicValue( context, rootClass.getTable() ); final BasicValue discriminatorColumnBinding = new BasicValue( context, rootClass.getTable() );
rootClass.setDiscriminator( discriminatorColumnBinding ); rootClass.setDiscriminator( discriminatorColumnBinding );
discriminatorColumn.linkWithValue( discriminatorColumnBinding ); discriminatorColumn.linkWithValue( discriminatorColumnBinding );
discriminatorColumnBinding.setTypeName( discriminatorColumn.getDiscriminatorTypeName() ); discriminatorColumnBinding.setTypeName( discriminatorColumn.getDiscriminatorTypeName() );

View File

@ -12,12 +12,9 @@
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.CollectionId; import org.hibernate.annotations.CollectionId;
import org.hibernate.annotations.NotFoundAction;
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.MetadataBuildingContext;
import org.hibernate.cfg.AnnotatedColumn; import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedJoinColumn; import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.IdGeneratorResolverSecondPass; import org.hibernate.cfg.IdGeneratorResolverSecondPass;
import org.hibernate.cfg.PropertyData; import org.hibernate.cfg.PropertyData;
import org.hibernate.cfg.PropertyInferredData; import org.hibernate.cfg.PropertyInferredData;
@ -71,7 +68,7 @@ protected boolean bindStarToManySecondPass(Map<String, PersistentClass> persiste
"id" "id"
); );
final AnnotatedColumn[] idColumns = AnnotatedColumn.buildColumnsFromAnnotations( final AnnotatedColumns idColumns = AnnotatedColumn.buildColumnsFromAnnotations(
new Column[] { collectionIdAnn.column() }, new Column[] { collectionIdAnn.column() },
null, null,
Nullability.FORCED_NOT_NULL, Nullability.FORCED_NOT_NULL,
@ -82,7 +79,7 @@ protected boolean bindStarToManySecondPass(Map<String, PersistentClass> persiste
); );
//we need to make sure all id columns must be not-null. //we need to make sure all id columns must be not-null.
for ( AnnotatedColumn idColumn:idColumns ) { for ( AnnotatedColumn idColumn : idColumns.getColumns() ) {
idColumn.setNullable( false ); idColumn.setNullable( false );
} }

View File

@ -12,8 +12,9 @@
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.OrderBy; import org.hibernate.annotations.OrderBy;
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.CollectionSecondPass;
import org.hibernate.cfg.AnnotatedColumn; import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.CollectionSecondPass;
import org.hibernate.cfg.PropertyHolder; import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.PropertyHolderBuilder; import org.hibernate.cfg.PropertyHolderBuilder;
import org.hibernate.cfg.SecondPass; import org.hibernate.cfg.SecondPass;
@ -87,7 +88,9 @@ private void bindIndex() {
} }
indexColumn.setPropertyHolder( valueHolder ); indexColumn.setPropertyHolder( valueHolder );
final BasicValueBinder valueBinder = new BasicValueBinder( BasicValueBinder.Kind.LIST_INDEX, buildingContext ); final BasicValueBinder valueBinder = new BasicValueBinder( BasicValueBinder.Kind.LIST_INDEX, buildingContext );
valueBinder.setColumns( new AnnotatedColumn[] { indexColumn } ); final AnnotatedColumns result = new AnnotatedColumns();
result.setColumns( new AnnotatedColumn[] { indexColumn } );
valueBinder.setColumns(result);
valueBinder.setReturnedClassName( Integer.class.getName() ); valueBinder.setReturnedClassName( Integer.class.getName() );
valueBinder.setType( property, getElementType(), null, null ); valueBinder.setType( property, getElementType(), null, null );
// valueBinder.setExplicitType( "integer" ); // valueBinder.setExplicitType( "integer" );
@ -95,7 +98,13 @@ private void bindIndex() {
indexColumn.linkWithValue( indexValue ); indexColumn.linkWithValue( indexValue );
listValueMapping.setIndex( indexValue ); listValueMapping.setIndex( indexValue );
listValueMapping.setBaseIndex( indexColumn.getBase() ); listValueMapping.setBaseIndex( indexColumn.getBase() );
if ( listValueMapping.isOneToMany() && !listValueMapping.getKey().isNullable() && !listValueMapping.isInverse() ) { createBackref( listValueMapping );
}
private void createBackref(List listValueMapping) {
if ( listValueMapping.isOneToMany()
&& !listValueMapping.getKey().isNullable()
&& !listValueMapping.isInverse() ) {
final String entityName = ( (OneToMany) listValueMapping.getElement() ).getReferencedEntityName(); final String entityName = ( (OneToMany) listValueMapping.getElement() ).getReferencedEntityName();
final PersistentClass referenced = buildingContext.getMetadataCollector().getEntityBinding( entityName ); final PersistentClass referenced = buildingContext.getMetadataCollector().getEntityBinding( entityName );
final IndexBackref backref = new IndexBackref(); final IndexBackref backref = new IndexBackref();

View File

@ -6,7 +6,6 @@
*/ */
package org.hibernate.cfg.annotations; package org.hibernate.cfg.annotations;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -22,11 +21,11 @@
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedClassType; import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.AnnotatedJoinColumns; import org.hibernate.cfg.AnnotatedJoinColumns;
import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.CollectionPropertyHolder; import org.hibernate.cfg.CollectionPropertyHolder;
import org.hibernate.cfg.CollectionSecondPass; import org.hibernate.cfg.CollectionSecondPass;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedJoinColumn; import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.InheritanceState; import org.hibernate.cfg.InheritanceState;
import org.hibernate.cfg.PropertyData; import org.hibernate.cfg.PropertyData;
@ -100,7 +99,6 @@ public void secondPass(Map<String, PersistentClass> persistentClasses)
mapKeyPropertyName, mapKeyPropertyName,
property, property,
isEmbedded, isEmbedded,
buildingContext,
mapKeyColumns, mapKeyColumns,
mapKeyManyToManyColumns, mapKeyManyToManyColumns,
inverseJoinColumns != null ? inverseJoinColumns.getPropertyName() : null inverseJoinColumns != null ? inverseJoinColumns.getPropertyName() : null
@ -123,7 +121,7 @@ private void makeOneToManyMapKeyColumnNullableIfNotInProperty(
if ( selectable.isFormula() ) { if ( selectable.isFormula() ) {
throw new AssertionFailure( "Map key mapped by @MapKeyColumn is a Formula" ); throw new AssertionFailure( "Map key mapped by @MapKeyColumn is a Formula" );
} }
Column column = (Column) selectable; final Column column = (Column) selectable;
if ( !column.isNullable() ) { if ( !column.isNullable() ) {
final PersistentClass persistentClass = ( ( OneToMany ) map.getElement() ).getAssociatedClass(); final PersistentClass persistentClass = ( ( OneToMany ) map.getElement() ).getAssociatedClass();
// check if the index column has been mapped by the associated entity to a property; // check if the index column has been mapped by the associated entity to a property;
@ -158,59 +156,153 @@ private void bindKeyFromAssociationTable(
String mapKeyPropertyName, String mapKeyPropertyName,
XProperty property, XProperty property,
boolean isEmbedded, boolean isEmbedded,
MetadataBuildingContext buildingContext, AnnotatedColumns mapKeyColumns,
AnnotatedColumn[] mapKeyColumns,
AnnotatedJoinColumns mapKeyManyToManyColumns, AnnotatedJoinColumns mapKeyManyToManyColumns,
String targetPropertyName) { String targetPropertyName) {
if ( mapKeyPropertyName != null ) { if ( mapKeyPropertyName != null ) {
//this is an EJB3 @MapKey //this is an EJB3 @MapKey
PersistentClass associatedClass = persistentClasses.get( elementType.getName() ); handleExplicitMapKey( elementType, persistentClasses, mapKeyPropertyName );
}
else {
//this is a true Map mapping
final String mapKeyType = getKeyType( property );
final PersistentClass collectionEntity = persistentClasses.get( mapKeyType );
final boolean isIndexOfEntities = collectionEntity != null;
final ManyToOne element;
org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
if ( isIndexOfEntities ) {
element = handleCollectionKeyedByEntities( buildingContext, mapKeyType, map );
}
else {
element = null;
final XClass keyClass;
final AnnotatedClassType classType;
if ( PRIMITIVE_NAMES.contains( mapKeyType ) ) {
classType = AnnotatedClassType.NONE;
keyClass = null;
}
else {
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
final Class<Object> mapKeyClass = bootstrapContext.getClassLoaderAccess().classForName( mapKeyType );
keyClass = bootstrapContext.getReflectionManager().toXClass( mapKeyClass );
// force in case of attribute override naming the key
classType = isEmbedded || mappingDefinedAttributeOverrideOnMapKey( property )
? AnnotatedClassType.EMBEDDABLE
: buildingContext.getMetadataCollector().getClassType( keyClass );
}
handleIndex(
property,
mapKeyColumns,
mapKeyType,
map,
keyClass,
classType,
buildCollectionPropertyHolder( property, map, keyClass ),
getAccessType( map )
);
}
//FIXME pass the Index Entity JoinColumns
if ( !collection.isOneToMany() ) {
//index column should not be null
for ( AnnotatedJoinColumn column : mapKeyManyToManyColumns.getColumns() ) {
column.forceNotNull();
}
}
if ( element != null ) {
handleForeignKey( property, element );
}
if ( isIndexOfEntities ) {
bindManyToManyInverseForeignKey(
collectionEntity,
mapKeyManyToManyColumns,
element,
false //a map key column has no unique constraint
);
}
}
}
private static String getKeyType(XProperty property) {
//target has priority over reflection for the map key type
//JPA 2 has priority
final Class<?> target = property.isAnnotationPresent( MapKeyClass.class )
? property.getAnnotation( MapKeyClass.class ).value()
: void.class;
return void.class.equals( target ) ? property.getMapKey().getName() : target.getName();
}
private void handleExplicitMapKey(
XClass elementType,
Map<String, PersistentClass> persistentClasses,
String mapKeyPropertyName) {
final PersistentClass associatedClass = persistentClasses.get( elementType.getName() );
if ( associatedClass == null ) { if ( associatedClass == null ) {
throw new AnnotationException( "Association '" + safeCollectionRole() throw new AnnotationException( "Association '" + safeCollectionRole()
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" ); + "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
} }
Property mapProperty = findPropertyByName( associatedClass, mapKeyPropertyName ); final Property mapProperty = findPropertyByName( associatedClass, mapKeyPropertyName);
if ( mapProperty == null ) { if ( mapProperty == null ) {
throw new AnnotationException( "Map key property '" + mapKeyPropertyName throw new AnnotationException( "Map key property '" + mapKeyPropertyName
+ "' not found in target entity '" + associatedClass.getEntityName() + "'" ); + "' not found in target entity '" + associatedClass.getEntityName() + "'" );
} }
org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection; final org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
// HHH-11005 - if InheritanceType.JOINED then need to find class defining the column // HHH-11005 - if InheritanceType.JOINED then need to find class defining the column
InheritanceState inheritanceState = inheritanceStatePerClass.get( elementType ); final InheritanceState inheritanceState = inheritanceStatePerClass.get(elementType);
PersistentClass targetPropertyPersistentClass = InheritanceType.JOINED.equals( inheritanceState.getType() ) ? final PersistentClass targetEntity = InheritanceType.JOINED == inheritanceState.getType()
mapProperty.getPersistentClass() : ? mapProperty.getPersistentClass()
associatedClass; : associatedClass;
Value indexValue = createFormulatedValue( final Value indexValue = createFormulatedValue( mapProperty.getValue(), map, associatedClass, targetEntity );
mapProperty.getValue(), map, targetPropertyName, associatedClass, targetPropertyPersistentClass, buildingContext
);
map.setIndex( indexValue ); map.setIndex( indexValue );
map.setMapKeyPropertyName(mapKeyPropertyName); map.setMapKeyPropertyName(mapKeyPropertyName);
} }
else {
//this is a true Map mapping private CollectionPropertyHolder buildCollectionPropertyHolder(
//TODO ugly copy/paste from CollectionBinder.bindManyToManySecondPass XProperty property,
String mapKeyType; org.hibernate.mapping.Map map,
Class<?> target = void.class; XClass keyClass) {
/* final CollectionPropertyHolder holder = buildPropertyHolder(
* target has priority over reflection for the map key type map,
* JPA 2 has priority qualify( map.getRole(), "mapkey" ),
*/ keyClass,
if ( property.isAnnotationPresent( MapKeyClass.class ) ) { property,
target = property.getAnnotation( MapKeyClass.class ).value(); propertyHolder,
buildingContext
);
// 'propertyHolder' is the PropertyHolder for the owner of the collection
// 'holder' is the CollectionPropertyHolder.
// 'property' is the collection XProperty
propertyHolder.startingProperty(property);
holder.prepare(property);
return holder;
} }
if ( !void.class.equals( target ) ) {
mapKeyType = target.getName(); private void handleForeignKey(XProperty property, ManyToOne element) {
final jakarta.persistence.ForeignKey foreignKey = getMapKeyForeignKey( property );
if ( foreignKey != null ) {
final ConstraintMode constraintMode = foreignKey.value();
if ( constraintMode == ConstraintMode.NO_CONSTRAINT
|| constraintMode == ConstraintMode.PROVIDER_DEFAULT
&& getBuildingContext().getBuildingOptions().isNoConstraintByDefault() ) {
element.disableForeignKey();
} }
else { else {
mapKeyType = property.getMapKey().getName(); element.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
element.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
} }
PersistentClass collectionEntity = persistentClasses.get( mapKeyType ); }
boolean isIndexOfEntities = collectionEntity != null; }
ManyToOne element = null;
org.hibernate.mapping.Map mapValue = (org.hibernate.mapping.Map) this.collection; //similar to CollectionBinder.handleCollectionOfEntities()
if ( isIndexOfEntities ) { private static ManyToOne handleCollectionKeyedByEntities(
element = new ManyToOne( buildingContext, mapValue.getCollectionTable() ); MetadataBuildingContext context,
mapValue.setIndex( element ); String mapKeyType,
org.hibernate.mapping.Map map) {
final ManyToOne element;
element = new ManyToOne(context, map.getCollectionTable() );
map.setIndex( element );
element.setReferencedEntityName(mapKeyType); element.setReferencedEntityName(mapKeyType);
//element.setFetchMode( fetchMode ); //element.setFetchMode( fetchMode );
//element.setLazy( fetchMode != FetchMode.JOIN ); //element.setLazy( fetchMode != FetchMode.JOIN );
@ -218,44 +310,12 @@ private void bindKeyFromAssociationTable(
element.setFetchMode( FetchMode.JOIN ); element.setFetchMode( FetchMode.JOIN );
element.setLazy( false ); element.setLazy( false );
//does not make sense for a map key element.setIgnoreNotFound( ignoreNotFound ); //does not make sense for a map key element.setIgnoreNotFound( ignoreNotFound );
} return element;
else {
final XClass keyXClass;
AnnotatedClassType classType;
if ( PRIMITIVE_NAMES.contains( mapKeyType ) ) {
classType = AnnotatedClassType.NONE;
keyXClass = null;
}
else {
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
final Class<Object> mapKeyClass = bootstrapContext.getClassLoaderAccess().classForName( mapKeyType );
keyXClass = bootstrapContext.getReflectionManager().toXClass( mapKeyClass );
classType = buildingContext.getMetadataCollector().getClassType( keyXClass );
// force in case of attribute override naming the key
if ( isEmbedded || mappingDefinedAttributeOverrideOnMapKey( property ) ) {
classType = AnnotatedClassType.EMBEDDABLE;
}
} }
CollectionPropertyHolder holder = buildPropertyHolder( private static AccessType getAccessType(org.hibernate.mapping.Map map) {
mapValue, final PersistentClass owner = map.getOwner();
qualify( mapValue.getRole(), "mapkey" ), final AccessType accessType;
keyXClass,
property,
propertyHolder,
buildingContext
);
// 'propertyHolder' is the PropertyHolder for the owner of the collection
// 'holder' is the CollectionPropertyHolder.
// 'property' is the collection XProperty
propertyHolder.startingProperty( property );
holder.prepare( property );
PersistentClass owner = mapValue.getOwner();
AccessType accessType;
// FIXME support @Access for collection of elements // FIXME support @Access for collection of elements
// String accessType = access != null ? access.value() : null; // String accessType = access != null ? access.value() : null;
if ( owner.getIdentifierProperty() != null ) { if ( owner.getIdentifierProperty() != null ) {
@ -272,21 +332,32 @@ else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().get
else { else {
throw new AssertionFailure( "Unable to guess collection property accessor name" ); throw new AssertionFailure( "Unable to guess collection property accessor name" );
} }
return accessType;
}
private void handleIndex(
XProperty property,
AnnotatedColumns mapKeyColumns,
String mapKeyType,
org.hibernate.mapping.Map map,
XClass keyClass,
AnnotatedClassType classType,
CollectionPropertyHolder holder,
AccessType accessType) {
final Class<? extends CompositeUserType<?>> compositeUserType = resolveCompositeUserType( final Class<? extends CompositeUserType<?>> compositeUserType = resolveCompositeUserType(
property, property,
keyXClass, keyClass,
buildingContext buildingContext
); );
if ( AnnotatedClassType.EMBEDDABLE.equals( classType ) || compositeUserType != null ) {
EntityBinder entityBinder = new EntityBinder();
PropertyData inferredData = isHibernateExtensionMapping() if ( AnnotatedClassType.EMBEDDABLE == classType || compositeUserType != null ) {
? new PropertyPreloadedData(AccessType.PROPERTY, "index", keyXClass) final EntityBinder entityBinder = new EntityBinder();
: new PropertyPreloadedData(AccessType.PROPERTY, "key", keyXClass); final PropertyData inferredData = isHibernateExtensionMapping()
? new PropertyPreloadedData( AccessType.PROPERTY, "index", keyClass)
// "key" is the JPA 2 prefix for map keys // "key" is the JPA 2 prefix for map keys
: new PropertyPreloadedData( AccessType.PROPERTY, "key", keyClass);
//TODO be smart with isNullable //TODO be smart with isNullable
Component component = AnnotationBinder.fillComponent( final Component component = AnnotationBinder.fillComponent(
holder, holder,
inferredData, inferredData,
accessType, accessType,
@ -300,76 +371,30 @@ else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().get
buildingContext, buildingContext,
inheritanceStatePerClass inheritanceStatePerClass
); );
mapValue.setIndex( component ); map.setIndex( component );
} }
else { else {
final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext ); final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext );
elementBinder.setReturnedClassName(mapKeyType); elementBinder.setReturnedClassName(mapKeyType);
final AnnotatedColumns keyColumns = createElementColumnsIfNecessary(
AnnotatedColumn[] elementColumns = mapKeyColumns; collection,
if ( elementColumns == null || elementColumns.length == 0 ) { mapKeyColumns,
elementColumns = new AnnotatedColumn[1]; Collection.DEFAULT_KEY_COLUMN_NAME,
AnnotatedColumn column = new AnnotatedColumn(); Size.DEFAULT_LENGTH, //TODO: is this really necessary??!!
column.setImplicit( false ); buildingContext
column.setNullable( true ); );
column.setLength( Size.DEFAULT_LENGTH ); elementBinder.setColumns( keyColumns );
column.setLogicalColumnName( Collection.DEFAULT_KEY_COLUMN_NAME );
//TODO create an EMPTY_JOINS collection
column.setJoins( new HashMap<>() );
column.setBuildingContext( buildingContext );
column.bind();
elementColumns[0] = column;
}
//override the table
for (AnnotatedColumn column : elementColumns) {
column.setTable( mapValue.getCollectionTable() );
}
elementBinder.setColumns( elementColumns );
//do not call setType as it extracts the type from @Type //do not call setType as it extracts the type from @Type
//the algorithm generally does not apply for map key anyway //the algorithm generally does not apply for map key anyway
elementBinder.setType( elementBinder.setType(
property, property,
keyXClass, keyClass,
this.collection.getOwnerEntityName(), collection.getOwnerEntityName(),
holder.mapKeyAttributeConverterDescriptor( property, keyXClass ) holder.mapKeyAttributeConverterDescriptor(property, keyClass)
); );
elementBinder.setPersistentClassName( propertyHolder.getEntityName() ); elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
elementBinder.setAccessType(accessType); elementBinder.setAccessType(accessType);
mapValue.setIndex( elementBinder.make() ); map.setIndex( elementBinder.make() );
}
}
//FIXME pass the Index Entity JoinColumns
if ( !collection.isOneToMany() ) {
//index column should not be null
for ( AnnotatedJoinColumn col : mapKeyManyToManyColumns.getColumns() ) {
col.forceNotNull();
}
}
if ( element != null ) {
final jakarta.persistence.ForeignKey foreignKey = getMapKeyForeignKey( property );
if ( foreignKey != null ) {
if ( foreignKey.value() == ConstraintMode.NO_CONSTRAINT
|| foreignKey.value() == ConstraintMode.PROVIDER_DEFAULT
&& getBuildingContext().getBuildingOptions().isNoConstraintByDefault() ) {
element.disableForeignKey();
}
else {
element.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
element.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
}
}
}
if ( isIndexOfEntities ) {
bindManyToManyInverseForeignKey(
collectionEntity,
mapKeyManyToManyColumns,
element,
false, //a map key column has no unique constraint
buildingContext
);
}
} }
} }
@ -429,13 +454,11 @@ private boolean namedMapKey(AttributeOverride annotation) {
return annotation.name().startsWith( "key." ); return annotation.name().startsWith( "key." );
} }
protected Value createFormulatedValue( private Value createFormulatedValue(
Value value, Value value,
Collection collection, Collection collection,
String targetPropertyName,
PersistentClass associatedClass, PersistentClass associatedClass,
PersistentClass targetPropertyPersistentClass, PersistentClass targetPropertyPersistentClass) {
MetadataBuildingContext buildingContext) {
final Table mapKeyTable; final Table mapKeyTable;
// HHH-11005 - only if we are OneToMany and location of map key property is at a different level, need to add a select // HHH-11005 - only if we are OneToMany and location of map key property is at a different level, need to add a select
if ( !associatedClass.equals( targetPropertyPersistentClass ) ) { if ( !associatedClass.equals( targetPropertyPersistentClass ) ) {
@ -464,14 +487,7 @@ protected Value createFormulatedValue(
newProperty.setPropertyAccessorName( current.getPropertyAccessorName() ); newProperty.setPropertyAccessorName( current.getPropertyAccessorName() );
newProperty.setSelectable( current.isSelectable() ); newProperty.setSelectable( current.isSelectable() );
newProperty.setValue( newProperty.setValue(
createFormulatedValue( createFormulatedValue( current.getValue(), collection, associatedClass, associatedClass )
current.getValue(),
collection,
targetPropertyName,
associatedClass,
associatedClass,
buildingContext
)
); );
indexComponent.addProperty( newProperty ); indexComponent.addProperty( newProperty );
} }
@ -504,8 +520,8 @@ else if ( value instanceof SimpleValue ) {
SimpleValue sourceValue = (SimpleValue) value; SimpleValue sourceValue = (SimpleValue) value;
SimpleValue targetValue; SimpleValue targetValue;
if ( value instanceof ManyToOne ) { if ( value instanceof ManyToOne ) {
ManyToOne sourceManyToOne = (ManyToOne) sourceValue; final ManyToOne sourceManyToOne = (ManyToOne) sourceValue;
ManyToOne targetManyToOne = new ManyToOne( getBuildingContext(), mapKeyTable ); final ManyToOne targetManyToOne = new ManyToOne( getBuildingContext(), mapKeyTable );
targetManyToOne.setFetchMode( FetchMode.DEFAULT ); targetManyToOne.setFetchMode( FetchMode.DEFAULT );
targetManyToOne.setLazy( true ); targetManyToOne.setLazy( true );
//targetValue.setIgnoreNotFound( ); does not make sense for a map key //targetValue.setIgnoreNotFound( ); does not make sense for a map key

View File

@ -23,6 +23,7 @@
import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.AnnotatedColumn; import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.InheritanceState; import org.hibernate.cfg.InheritanceState;
@ -66,7 +67,7 @@ public class PropertyBinder {
private boolean lazy; private boolean lazy;
private String lazyGroup; private String lazyGroup;
private AccessType accessType; private AccessType accessType;
private AnnotatedColumn[] columns; private AnnotatedColumns columns;
private PropertyHolder holder; private PropertyHolder holder;
private Value value; private Value value;
private boolean insertable = true; private boolean insertable = true;
@ -128,9 +129,10 @@ public void setAccessType(AccessType accessType) {
this.accessType = accessType; this.accessType = accessType;
} }
public void setColumns(AnnotatedColumn[] columns) { public void setColumns(AnnotatedColumns columns) {
insertable = columns[0].isInsertable(); final AnnotatedColumn firstColumn = columns.getColumns()[0];
updatable = columns[0].isUpdatable(); insertable = firstColumn.isInsertable();
updatable = firstColumn.isUpdatable();
//consistency is checked later when we know the property name //consistency is checked later when we know the property name
this.columns = columns; this.columns = columns;
} }
@ -355,7 +357,7 @@ private void inferOptimisticLocking(Property prop) {
prop.setOptimisticLocked( ((Collection) value).isOptimisticLocked() ); prop.setOptimisticLocked( ((Collection) value).isOptimisticLocked() );
} }
else if ( property != null && property.isAnnotationPresent(OptimisticLock.class) ) { else if ( property != null && property.isAnnotationPresent(OptimisticLock.class) ) {
OptimisticLock lockAnn = property.getAnnotation(OptimisticLock.class); final OptimisticLock lockAnn = property.getAnnotation(OptimisticLock.class);
validateOptimisticLock(lockAnn); validateOptimisticLock(lockAnn);
prop.setOptimisticLocked( !lockAnn.excluded() ); prop.setOptimisticLocked( !lockAnn.excluded() );
} }

View File

@ -274,7 +274,6 @@ private void checkSelectable(Selectable incomingColumn) {
@Override @Override
public void addColumn(Column incomingColumn, boolean isInsertable, boolean isUpdatable) { public void addColumn(Column incomingColumn, boolean isInsertable, boolean isUpdatable) {
super.addColumn( incomingColumn, isInsertable, isUpdatable ); super.addColumn( incomingColumn, isInsertable, isUpdatable );
checkSelectable( incomingColumn ); checkSelectable( incomingColumn );
} }