introduce AnnotatedJoinColumns and remove deprecated stuff
This commit is contained in:
parent
ce12d4a586
commit
653bf987bd
|
@ -2824,9 +2824,8 @@ public class ModelBinder {
|
|||
}
|
||||
|
||||
String typeName = typeSource.getName();
|
||||
Map<String,String> typeParameters = new HashMap<>();
|
||||
|
||||
final TypeDefinition typeDefinition = sourceDocument.getMetadataCollector().getTypeDefinition( typeName );
|
||||
final Map<String,String> typeParameters = new HashMap<>();
|
||||
if ( typeDefinition != null ) {
|
||||
// the explicit name referred to a type-def
|
||||
typeName = typeDefinition.getTypeImplementorClass().getName();
|
||||
|
@ -3302,13 +3301,10 @@ public class ModelBinder {
|
|||
final String propRef = keySource.getReferencedPropertyName();
|
||||
getCollectionBinding().setReferencedPropertyName( propRef );
|
||||
|
||||
final KeyValue keyVal;
|
||||
if ( propRef == null ) {
|
||||
keyVal = getCollectionBinding().getOwner().getIdentifier();
|
||||
}
|
||||
else {
|
||||
keyVal = (KeyValue) getCollectionBinding().getOwner().getRecursiveProperty( propRef ).getValue();
|
||||
}
|
||||
final PersistentClass owner = getCollectionBinding().getOwner();
|
||||
final KeyValue keyVal = propRef == null
|
||||
? owner.getIdentifier()
|
||||
: (KeyValue) owner.getRecursiveProperty( propRef ).getValue();
|
||||
final DependantValue key = new DependantValue(
|
||||
mappingDocument,
|
||||
getCollectionBinding().getCollectionTable(),
|
||||
|
|
|
@ -44,7 +44,17 @@ import static org.hibernate.internal.util.StringHelper.isEmpty;
|
|||
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
||||
|
||||
/**
|
||||
* A {@link jakarta.persistence.Column} annotation
|
||||
* A mapping to a column, logically representing a
|
||||
* {@link jakarta.persistence.Column} annotation, but not
|
||||
* every instance corresponds to an explicit annotation in
|
||||
* the Java code.
|
||||
* <p>
|
||||
* This class holds a representation that is intermediate
|
||||
* between the annotation of the Java source code, and the
|
||||
* mapping model object {@link Column}. It's used only by
|
||||
* the {@link AnnotationBinder} while parsing annotations,
|
||||
* and does not survive into later stages of the startup
|
||||
* process.
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
|
@ -66,7 +76,7 @@ public class AnnotatedColumn {
|
|||
private Integer precision;
|
||||
private Integer scale;
|
||||
private String logicalColumnName;
|
||||
private String propertyName;
|
||||
private String propertyName; // this is really a .-separated property path
|
||||
private boolean unique;
|
||||
private boolean nullable = true;
|
||||
private String formulaString;
|
||||
|
@ -184,6 +194,9 @@ public class AnnotatedColumn {
|
|||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* A property path relative to the {@link #getPropertyHolder() PropertyHolder}.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
@ -328,7 +341,7 @@ public class AnnotatedColumn {
|
|||
|
||||
private String processColumnName(String columnName, boolean applyNamingStrategy) {
|
||||
if ( applyNamingStrategy ) {
|
||||
Database database = context.getMetadataCollector().getDatabase();
|
||||
final Database database = context.getMetadataCollector().getDatabase();
|
||||
return context.getBuildingOptions().getPhysicalNamingStrategy()
|
||||
.toPhysicalColumnName( database.toIdentifier( columnName ), database.getJdbcEnvironment() )
|
||||
.render( database.getDialect() );
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.cfg;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.PrimaryKeyJoinColumn;
|
||||
|
@ -16,26 +15,15 @@ import org.hibernate.AnnotationException;
|
|||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.JoinColumnOrFormula;
|
||||
import org.hibernate.annotations.JoinFormula;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.boot.model.naming.EntityNaming;
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.boot.model.naming.ImplicitJoinColumnNameSource;
|
||||
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
||||
import org.hibernate.boot.model.naming.ImplicitPrimaryKeyJoinColumnNameSource;
|
||||
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
||||
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.source.spi.AttributePath;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.MetadataBuildingOptions;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Join;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
|
@ -47,99 +35,35 @@ import static org.hibernate.cfg.BinderHelper.isEmptyAnnotationValue;
|
|||
import static org.hibernate.cfg.BinderHelper.isEmptyOrNullAnnotationValue;
|
||||
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
||||
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
||||
import static org.hibernate.internal.util.StringHelper.isQuoted;
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
import static org.hibernate.internal.util.StringHelper.unquote;
|
||||
|
||||
/**
|
||||
* A {@link jakarta.persistence.JoinColumn} annotation
|
||||
* An element of a join condition, logically representing a
|
||||
* {@link jakarta.persistence.JoinColumn} annotation, but not
|
||||
* every instance corresponds to an explicit annotation in the
|
||||
* Java code.
|
||||
* <p>
|
||||
* There's no exact analog of this class in the mapping model,
|
||||
* so some information is lost when it's transformed into a
|
||||
* {@link Column}.
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class AnnotatedJoinColumn extends AnnotatedColumn {
|
||||
|
||||
private String referencedColumn;
|
||||
|
||||
@Deprecated private String mappedBy;
|
||||
@Deprecated private String mappedByPropertyName; //property name on the owning side if any
|
||||
@Deprecated private String mappedByTableName; //table name on the mapped by side if any
|
||||
@Deprecated private String mappedByEntityName;
|
||||
@Deprecated private boolean JPA2ElementCollection;
|
||||
@Deprecated private String manyToManyOwnerSideEntityName;
|
||||
private AnnotatedJoinColumns parent;
|
||||
|
||||
// due to @AnnotationOverride overriding rules,
|
||||
// we don't want the constructor to be public
|
||||
private AnnotatedJoinColumn() {
|
||||
mappedBy = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this is not a column-level setting, so it's better to
|
||||
* hang this information somewhere else
|
||||
*/
|
||||
@Deprecated
|
||||
public void setJPA2ElementCollection(boolean JPA2ElementCollection) {
|
||||
this.JPA2ElementCollection = JPA2ElementCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this is not a column-level setting, so it's better to
|
||||
* get this information from somewhere else
|
||||
*/
|
||||
@Deprecated
|
||||
public String getManyToManyOwnerSideEntityName() {
|
||||
return manyToManyOwnerSideEntityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this is not a column-level setting, so it's better to
|
||||
* get this information from somewhere else
|
||||
*/
|
||||
@Deprecated
|
||||
public void setManyToManyOwnerSideEntityName(String manyToManyOwnerSideEntityName) {
|
||||
this.manyToManyOwnerSideEntityName = manyToManyOwnerSideEntityName;
|
||||
}
|
||||
private AnnotatedJoinColumn() {}
|
||||
|
||||
public void setReferencedColumn(String referencedColumn) {
|
||||
this.referencedColumn = referencedColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this is not a column-level setting, so it's better to
|
||||
* get this information from somewhere else
|
||||
*/
|
||||
@Deprecated
|
||||
public String getMappedBy() {
|
||||
return mappedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this is not column-level information, so it's better to
|
||||
* hang all this information somewhere else
|
||||
*/
|
||||
public void setMappedBy(String entityName, String logicalTableName, String mappedByProperty) {
|
||||
mappedByEntityName = entityName;
|
||||
mappedByTableName = logicalTableName;
|
||||
mappedByPropertyName = mappedByProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this is not a column-level setting, so it's better to
|
||||
* hang this information somewhere else
|
||||
*/
|
||||
@Deprecated
|
||||
public void setMappedBy(String mappedBy) {
|
||||
this.mappedBy = mappedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the association mapping annotation did specify
|
||||
* {@link jakarta.persistence.OneToMany#mappedBy() mappedBy},
|
||||
* meaning that this {@code @JoinColumn} mapping belongs to an
|
||||
* unowned many-valued association.
|
||||
*/
|
||||
public boolean hasMappedBy() {
|
||||
return !isEmptyOrNullAnnotationValue( mappedBy );
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link JoinColumn#referencedColumnName() referencedColumnName}.
|
||||
*/
|
||||
|
@ -155,138 +79,58 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
return isEmptyOrNullAnnotationValue( referencedColumn );
|
||||
}
|
||||
|
||||
public static AnnotatedJoinColumn[] buildJoinColumnsOrFormulas(
|
||||
JoinColumnOrFormula[] joinColumnOrFormulas,
|
||||
static AnnotatedJoinColumn buildJoinColumn(
|
||||
JoinColumn joinColumn,
|
||||
String mappedBy,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final AnnotatedJoinColumn[] joinColumns = new AnnotatedJoinColumn[joinColumnOrFormulas.length];
|
||||
for (int i = 0; i < joinColumnOrFormulas.length; i++) {
|
||||
JoinColumnOrFormula columnOrFormula = joinColumnOrFormulas[i];
|
||||
JoinFormula formula = columnOrFormula.formula();
|
||||
if ( formula.value() != null && !formula.value().isEmpty() ) {
|
||||
joinColumns[i] = buildJoinFormula( formula, joins, propertyHolder, propertyName, buildingContext );
|
||||
}
|
||||
else {
|
||||
joinColumns[i] = buildJoinColumn( mappedBy, joins, propertyHolder, propertyName, buildingContext, columnOrFormula );
|
||||
}
|
||||
final String path = qualify( propertyHolder.getPath(), propertyName );
|
||||
final JoinColumn[] overriddes = propertyHolder.getOverriddenJoinColumn( path );
|
||||
if ( overriddes != null ) {
|
||||
//TODO: relax this restriction
|
||||
throw new AnnotationException("Property '" + path
|
||||
+ "' overrides mapping specified using '@JoinColumnOrFormula'");
|
||||
}
|
||||
return joinColumns;
|
||||
}
|
||||
|
||||
private static AnnotatedJoinColumn buildJoinColumn(
|
||||
String mappedBy,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName, MetadataBuildingContext buildingContext,
|
||||
JoinColumnOrFormula join) {
|
||||
return buildJoinColumns(
|
||||
new JoinColumn[]{ join.column() },
|
||||
return buildJoinColumn(
|
||||
joinColumn,
|
||||
null,
|
||||
mappedBy,
|
||||
joins,
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
buildingContext
|
||||
)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* build join formula
|
||||
*/
|
||||
public static AnnotatedJoinColumn buildJoinFormula(
|
||||
JoinFormula joinFormula,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
AnnotatedJoinColumn formulaColumn = new AnnotatedJoinColumn();
|
||||
formulaColumn.setFormula( joinFormula.value() );
|
||||
formulaColumn.setReferencedColumn(joinFormula.referencedColumnName());
|
||||
formulaColumn.setBuildingContext( buildingContext );
|
||||
formulaColumn.setPropertyHolder( propertyHolder );
|
||||
formulaColumn.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
formulaColumn.setJoins( joins );
|
||||
formulaColumn.bind();
|
||||
return formulaColumn;
|
||||
}
|
||||
|
||||
public static AnnotatedJoinColumn[] buildJoinColumns(
|
||||
JoinColumn[] joinColumns,
|
||||
Comment comment,
|
||||
String mappedBy,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
return buildJoinColumnsWithDefaultColumnSuffix(
|
||||
joinColumns,
|
||||
comment,
|
||||
mappedBy,
|
||||
joins,
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
"",
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
public static AnnotatedJoinColumn[] buildJoinColumnsWithDefaultColumnSuffix(
|
||||
JoinColumn[] joinColumns,
|
||||
public static AnnotatedJoinColumn buildJoinFormula(
|
||||
JoinFormula joinFormula,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final AnnotatedJoinColumn formulaColumn = new AnnotatedJoinColumn();
|
||||
formulaColumn.setFormula( joinFormula.value() );
|
||||
formulaColumn.setReferencedColumn( joinFormula.referencedColumnName() );
|
||||
formulaColumn.setBuildingContext( buildingContext );
|
||||
formulaColumn.setPropertyHolder( propertyHolder );
|
||||
formulaColumn.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
formulaColumn.setJoins( joins );
|
||||
formulaColumn.bind();
|
||||
return formulaColumn;
|
||||
}
|
||||
|
||||
static AnnotatedJoinColumn buildJoinColumn(
|
||||
JoinColumn joinColumn,
|
||||
Comment comment,
|
||||
String mappedBy,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
String suffixForDefaultColumnName,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
JoinColumn[] overriddes = propertyHolder.getOverriddenJoinColumn( qualify( propertyHolder.getPath(), propertyName ) );
|
||||
JoinColumn[] actualColumns = overriddes == null ? joinColumns : overriddes;
|
||||
if ( actualColumns == null || actualColumns.length == 0 ) {
|
||||
return new AnnotatedJoinColumn[] {
|
||||
buildJoinColumn(
|
||||
null,
|
||||
comment,
|
||||
mappedBy,
|
||||
joins,
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
suffixForDefaultColumnName,
|
||||
buildingContext
|
||||
)
|
||||
};
|
||||
}
|
||||
else {
|
||||
final AnnotatedJoinColumn[] result = new AnnotatedJoinColumn[actualColumns.length];
|
||||
for (int index = 0; index < actualColumns.length; index++ ) {
|
||||
result[index] = buildJoinColumn(
|
||||
actualColumns[index],
|
||||
comment,
|
||||
mappedBy,
|
||||
joins,
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
suffixForDefaultColumnName,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* build join column for SecondaryTables
|
||||
*/
|
||||
private static AnnotatedJoinColumn buildJoinColumn(
|
||||
JoinColumn joinColumn,
|
||||
Comment comment,
|
||||
String mappedBy, Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
String suffixForDefaultColumnName,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
String defaultColumnSuffix,
|
||||
MetadataBuildingContext context) {
|
||||
if ( joinColumn != null ) {
|
||||
if ( !isEmptyOrNullAnnotationValue( mappedBy ) ) {
|
||||
throw new AnnotationException(
|
||||
|
@ -294,40 +138,59 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
+ "' is 'mappedBy' a different entity and may not explicitly specify the '@JoinColumn'"
|
||||
);
|
||||
}
|
||||
AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setComment( comment != null ? comment.value() : null );
|
||||
column.setBuildingContext( buildingContext );
|
||||
column.setJoinAnnotation( joinColumn, null );
|
||||
if ( isEmpty( column.getLogicalColumnName() ) && isNotEmpty( suffixForDefaultColumnName ) ) {
|
||||
column.setLogicalColumnName( propertyName + suffixForDefaultColumnName );
|
||||
}
|
||||
column.setJoins( joins );
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
column.setImplicit( false );
|
||||
column.bind();
|
||||
return column;
|
||||
return explicitJoinColumn( joinColumn, comment, joins, propertyHolder, propertyName, defaultColumnSuffix, context );
|
||||
}
|
||||
else {
|
||||
AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setMappedBy( mappedBy );
|
||||
column.setJoins( joins );
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
// property name + suffix is an "explicit" column name
|
||||
if ( isNotEmpty( suffixForDefaultColumnName ) ) {
|
||||
column.setLogicalColumnName( propertyName + suffixForDefaultColumnName );
|
||||
column.setImplicit( false );
|
||||
}
|
||||
else {
|
||||
column.setImplicit( true );
|
||||
}
|
||||
column.setBuildingContext( buildingContext );
|
||||
column.bind();
|
||||
return column;
|
||||
return implicitJoinColumn( joins, propertyHolder, propertyName, defaultColumnSuffix, context );
|
||||
}
|
||||
}
|
||||
|
||||
private static AnnotatedJoinColumn explicitJoinColumn(
|
||||
JoinColumn joinColumn,
|
||||
Comment comment,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
String defaultColumnSuffix,
|
||||
MetadataBuildingContext context) {
|
||||
final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setComment( comment != null ? comment.value() : null );
|
||||
column.setBuildingContext( context );
|
||||
column.setJoinAnnotation(joinColumn, null );
|
||||
if ( isEmpty( column.getLogicalColumnName() ) && isNotEmpty( defaultColumnSuffix ) ) {
|
||||
column.setLogicalColumnName( propertyName + defaultColumnSuffix );
|
||||
}
|
||||
column.setJoins( joins );
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
column.setImplicit( false );
|
||||
column.bind();
|
||||
return column;
|
||||
}
|
||||
|
||||
private static AnnotatedJoinColumn implicitJoinColumn(
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
String defaultColumnSuffix,
|
||||
MetadataBuildingContext context) {
|
||||
final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setJoins( joins );
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
// property name + suffix is an "explicit" column name
|
||||
if ( isNotEmpty( defaultColumnSuffix ) ) {
|
||||
column.setLogicalColumnName( propertyName + defaultColumnSuffix );
|
||||
column.setImplicit( false );
|
||||
}
|
||||
else {
|
||||
column.setImplicit( true );
|
||||
}
|
||||
column.setBuildingContext( context );
|
||||
column.bind();
|
||||
return column;
|
||||
}
|
||||
|
||||
|
||||
// TODO default name still useful in association table
|
||||
public void setJoinAnnotation(JoinColumn joinColumn, String defaultName) {
|
||||
|
@ -337,7 +200,8 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
else {
|
||||
setImplicit( false );
|
||||
if ( !isEmptyAnnotationValue( joinColumn.columnDefinition() ) ) {
|
||||
setSqlType( getBuildingContext().getObjectNameNormalizer().applyGlobalQuoting( joinColumn.columnDefinition() ) );
|
||||
setSqlType( getBuildingContext().getObjectNameNormalizer()
|
||||
.applyGlobalQuoting( joinColumn.columnDefinition() ) );
|
||||
}
|
||||
if ( !isEmptyAnnotationValue( joinColumn.name() ) ) {
|
||||
setLogicalColumnName( joinColumn.name() );
|
||||
|
@ -372,72 +236,67 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
MetadataBuildingContext context) {
|
||||
|
||||
final String defaultColumnName = context.getMetadataCollector().getLogicalColumnName(
|
||||
identifier.getTable(),
|
||||
identifier.getColumns().get(0).getQuotedName()
|
||||
);
|
||||
final ObjectNameNormalizer normalizer = context.getObjectNameNormalizer();
|
||||
|
||||
if ( primaryKeyJoinColumn != null || joinColumn != null ) {
|
||||
final String columnName;
|
||||
final String columnDefinition;
|
||||
final String referencedColumnName;
|
||||
if ( primaryKeyJoinColumn != null ) {
|
||||
columnName = primaryKeyJoinColumn.name();
|
||||
columnDefinition = primaryKeyJoinColumn.columnDefinition();
|
||||
referencedColumnName = primaryKeyJoinColumn.referencedColumnName();
|
||||
}
|
||||
else {
|
||||
columnName = joinColumn.name();
|
||||
columnDefinition = joinColumn.columnDefinition();
|
||||
referencedColumnName = joinColumn.referencedColumnName();
|
||||
}
|
||||
final String columnDef = columnDefinition.isEmpty() ? null
|
||||
: normalizer.toDatabaseIdentifierText( columnDefinition );
|
||||
final String logicalColumnName = columnName != null && columnName.isEmpty()
|
||||
? normalizer.normalizeIdentifierQuotingAsString( defaultColumnName )
|
||||
: normalizer.normalizeIdentifierQuotingAsString( columnName );
|
||||
AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setSqlType( columnDef );
|
||||
column.setLogicalColumnName( logicalColumnName );
|
||||
column.setReferencedColumn( referencedColumnName );
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
column.setJoins( joins );
|
||||
column.setBuildingContext( context );
|
||||
column.setImplicit( false );
|
||||
column.setNullable( false );
|
||||
column.bind();
|
||||
return column;
|
||||
}
|
||||
else {
|
||||
AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setLogicalColumnName( normalizer.normalizeIdentifierQuotingAsString( defaultColumnName ) );
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
column.setJoins( joins );
|
||||
column.setBuildingContext( context );
|
||||
column.setImplicit( true );
|
||||
column.setNullable( false );
|
||||
column.bind();
|
||||
return column;
|
||||
}
|
||||
final String defaultColumnName = context.getMetadataCollector()
|
||||
.getLogicalColumnName( identifier.getTable(), identifier.getColumns().get(0).getQuotedName() );
|
||||
return primaryKeyJoinColumn != null || joinColumn != null
|
||||
? explicitJoinColumn( primaryKeyJoinColumn, joinColumn, joins, propertyHolder, context, defaultColumnName )
|
||||
: implicitJoinColumn( joins, propertyHolder, context, defaultColumnName );
|
||||
}
|
||||
|
||||
/**
|
||||
* Override persistent class on oneToMany Cases for late settings
|
||||
* Must only be used on second level pass binding
|
||||
*/
|
||||
public void setPersistentClass(
|
||||
PersistentClass persistentClass,
|
||||
private static AnnotatedJoinColumn explicitJoinColumn(
|
||||
PrimaryKeyJoinColumn primaryKeyJoinColumn,
|
||||
JoinColumn joinColumn,
|
||||
Map<String, Join> joins,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
// TODO shouldn't we deduce the classname from the persistentClass?
|
||||
this.propertyHolder = PropertyHolderBuilder.buildPropertyHolder(
|
||||
persistentClass,
|
||||
joins,
|
||||
getBuildingContext(),
|
||||
inheritanceStatePerClass
|
||||
);
|
||||
PropertyHolder propertyHolder,
|
||||
MetadataBuildingContext context,
|
||||
String defaultColumnName) {
|
||||
final String columnName;
|
||||
final String columnDefinition;
|
||||
final String referencedColumnName;
|
||||
if ( primaryKeyJoinColumn != null ) {
|
||||
columnName = primaryKeyJoinColumn.name();
|
||||
columnDefinition = primaryKeyJoinColumn.columnDefinition();
|
||||
referencedColumnName = primaryKeyJoinColumn.referencedColumnName();
|
||||
}
|
||||
else {
|
||||
columnName = joinColumn.name();
|
||||
columnDefinition = joinColumn.columnDefinition();
|
||||
referencedColumnName = joinColumn.referencedColumnName();
|
||||
}
|
||||
final ObjectNameNormalizer normalizer = context.getObjectNameNormalizer();
|
||||
final String columnDef = columnDefinition.isEmpty() ? null
|
||||
: normalizer.toDatabaseIdentifierText( columnDefinition );
|
||||
final String logicalColumnName = columnName != null && columnName.isEmpty()
|
||||
? normalizer.normalizeIdentifierQuotingAsString(defaultColumnName)
|
||||
: normalizer.normalizeIdentifierQuotingAsString( columnName );
|
||||
final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setSqlType( columnDef );
|
||||
column.setLogicalColumnName( logicalColumnName );
|
||||
column.setReferencedColumn( referencedColumnName );
|
||||
column.setPropertyHolder(propertyHolder);
|
||||
column.setJoins(joins);
|
||||
column.setBuildingContext(context);
|
||||
column.setImplicit( false );
|
||||
column.setNullable( false );
|
||||
column.bind();
|
||||
return column;
|
||||
}
|
||||
|
||||
private static AnnotatedJoinColumn implicitJoinColumn(
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
MetadataBuildingContext context,
|
||||
String defaultColumnName ) {
|
||||
final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
final ObjectNameNormalizer normalizer = context.getObjectNameNormalizer();
|
||||
column.setLogicalColumnName( normalizer.normalizeIdentifierQuotingAsString(defaultColumnName) );
|
||||
column.setPropertyHolder(propertyHolder);
|
||||
column.setJoins(joins);
|
||||
column.setBuildingContext(context);
|
||||
column.setImplicit( true );
|
||||
column.setNullable( false );
|
||||
column.bind();
|
||||
return column;
|
||||
}
|
||||
|
||||
public static void checkIfJoinColumn(Object columns, PropertyHolder holder, PropertyData property) {
|
||||
|
@ -467,281 +326,32 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
Column referencedColumn,
|
||||
PersistentClass referencedEntity,
|
||||
SimpleValue value) {
|
||||
String logicalReferencedColumn = getBuildingContext().getMetadataCollector().getLogicalColumnName(
|
||||
referencedEntity.getTable(),
|
||||
referencedColumn.getQuotedName()
|
||||
);
|
||||
String columnName = buildDefaultColumnName( referencedEntity, logicalReferencedColumn );
|
||||
|
||||
final String logicalReferencedColumn = getBuildingContext().getMetadataCollector()
|
||||
.getLogicalColumnName( referencedEntity.getTable(), referencedColumn.getQuotedName() );
|
||||
final String columnName = parent.buildDefaultColumnName( referencedEntity, logicalReferencedColumn );
|
||||
//yuk side effect on an implicit column
|
||||
setLogicalColumnName( columnName );
|
||||
setReferencedColumn( logicalReferencedColumn );
|
||||
final Column mappingColumn = getMappingColumn();
|
||||
initMappingColumn(
|
||||
columnName,
|
||||
null, referencedColumn.getLength(),
|
||||
referencedColumn.getPrecision(),
|
||||
referencedColumn.getScale(),
|
||||
getMappingColumn() != null && getMappingColumn().isNullable(),
|
||||
mappingColumn != null && mappingColumn.isNullable(),
|
||||
referencedColumn.getSqlType(),
|
||||
getMappingColumn() != null && getMappingColumn().isUnique(),
|
||||
mappingColumn != null && mappingColumn.isUnique(),
|
||||
false
|
||||
);
|
||||
linkWithValue( value );
|
||||
}
|
||||
|
||||
public void addDefaultJoinColumnName(PersistentClass referencedEntity, String logicalReferencedColumn) {
|
||||
final String columnName = buildDefaultColumnName( referencedEntity, logicalReferencedColumn );
|
||||
final String columnName = parent.buildDefaultColumnName( referencedEntity, logicalReferencedColumn );
|
||||
getMappingColumn().setName( columnName );
|
||||
setLogicalColumnName( columnName );
|
||||
}
|
||||
|
||||
private String buildDefaultColumnName(final PersistentClass referencedEntity, final String logicalReferencedColumn) {
|
||||
final InFlightMetadataCollector collector = getBuildingContext().getMetadataCollector();
|
||||
final Database database = collector.getDatabase();
|
||||
final MetadataBuildingOptions options = getBuildingContext().getBuildingOptions();
|
||||
final ImplicitNamingStrategy implicitNamingStrategy = options.getImplicitNamingStrategy();
|
||||
final PhysicalNamingStrategy physicalNamingStrategy = options.getPhysicalNamingStrategy();
|
||||
|
||||
boolean mappedBySide = mappedByTableName != null || mappedByPropertyName != null;
|
||||
boolean ownerSide = getPropertyName() != null;
|
||||
boolean isRefColumnQuoted = StringHelper.isQuoted( logicalReferencedColumn );
|
||||
|
||||
Identifier columnIdentifier;
|
||||
if ( mappedBySide ) {
|
||||
// NOTE : While it is completely misleading here to allow for the combination
|
||||
// of a "JPA ElementCollection" to be mappedBy, the code that uses this
|
||||
// class relies on this behavior for handling the inverse side of
|
||||
// many-to-many mappings
|
||||
columnIdentifier = implicitNamingStrategy.determineJoinColumnName(
|
||||
new ImplicitJoinColumnNameSource() {
|
||||
final AttributePath attributePath = AttributePath.parse( mappedByPropertyName );
|
||||
final ImplicitJoinColumnNameSource.Nature implicitNamingNature = getImplicitNature();
|
||||
|
||||
private final EntityNaming entityNaming = new EntityNaming() {
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return referencedEntity.getClassName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityName() {
|
||||
return referencedEntity.getEntityName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJpaEntityName() {
|
||||
return referencedEntity.getJpaEntityName();
|
||||
}
|
||||
};
|
||||
|
||||
private final Identifier referencedTableName = database.toIdentifier( mappedByTableName );
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return implicitNamingNature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityNaming getEntityNaming() {
|
||||
return entityNaming;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributePath getAttributePath() {
|
||||
return attributePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedTableName() {
|
||||
return referencedTableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedColumnName() {
|
||||
if ( logicalReferencedColumn != null ) {
|
||||
return database.toIdentifier( logicalReferencedColumn );
|
||||
}
|
||||
|
||||
if ( mappedByEntityName == null || mappedByPropertyName == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Property mappedByProperty = collector.getEntityBinding( mappedByEntityName )
|
||||
.getProperty( mappedByPropertyName );
|
||||
final SimpleValue value = (SimpleValue) mappedByProperty.getValue();
|
||||
if ( value.getSelectables().isEmpty() ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"Association '%s' is 'mappedBy' a property '%s' of entity '%s' with no columns",
|
||||
propertyHolder.getPath(),
|
||||
mappedByPropertyName,
|
||||
mappedByEntityName
|
||||
)
|
||||
);
|
||||
}
|
||||
final Selectable selectable = value.getSelectables().get(0);
|
||||
if ( !(selectable instanceof Column) ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"Association '%s' is 'mappedBy' a property '%s' of entity '%s' which maps to a formula",
|
||||
propertyHolder.getPath(),
|
||||
mappedByPropertyName,
|
||||
propertyHolder.getPath()
|
||||
)
|
||||
);
|
||||
}
|
||||
if ( value.getSelectables().size()>1 ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"Association '%s' is 'mappedBy' a property '%s' of entity '%s' with multiple columns",
|
||||
propertyHolder.getPath(),
|
||||
mappedByPropertyName,
|
||||
propertyHolder.getPath()
|
||||
)
|
||||
);
|
||||
}
|
||||
return database.toIdentifier( ( (Column) selectable ).getQuotedName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return AnnotatedJoinColumn.this.getBuildingContext();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
//one element was quoted so we quote
|
||||
if ( isRefColumnQuoted || StringHelper.isQuoted( mappedByTableName ) ) {
|
||||
columnIdentifier = Identifier.quote( columnIdentifier );
|
||||
}
|
||||
}
|
||||
else if ( ownerSide ) {
|
||||
final String logicalTableName = collector.getLogicalTableName( referencedEntity.getTable() );
|
||||
|
||||
columnIdentifier = implicitNamingStrategy.determineJoinColumnName(
|
||||
new ImplicitJoinColumnNameSource() {
|
||||
final ImplicitJoinColumnNameSource.Nature implicitNamingNature = getImplicitNature();
|
||||
|
||||
private final EntityNaming entityNaming = new EntityNaming() {
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return referencedEntity.getClassName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityName() {
|
||||
return referencedEntity.getEntityName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJpaEntityName() {
|
||||
return referencedEntity.getJpaEntityName();
|
||||
}
|
||||
};
|
||||
|
||||
private final AttributePath attributePath = AttributePath.parse( getPropertyName() );
|
||||
private final Identifier referencedTableName = database.toIdentifier( logicalTableName );
|
||||
private final Identifier referencedColumnName = database.toIdentifier( logicalReferencedColumn );
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return implicitNamingNature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityNaming getEntityNaming() {
|
||||
return entityNaming;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributePath getAttributePath() {
|
||||
return attributePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedTableName() {
|
||||
return referencedTableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedColumnName() {
|
||||
return referencedColumnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return AnnotatedJoinColumn.this.getBuildingContext();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// HHH-11826 magic. See Ejb3Column and the HHH-6005 comments
|
||||
if ( columnIdentifier.getText().contains( "_collection&&element_" ) ) {
|
||||
columnIdentifier = Identifier.toIdentifier(
|
||||
columnIdentifier.getText().replace( "_collection&&element_", "_" ),
|
||||
columnIdentifier.isQuoted()
|
||||
);
|
||||
}
|
||||
|
||||
//one element was quoted so we quote
|
||||
if ( isRefColumnQuoted || StringHelper.isQuoted( logicalTableName ) ) {
|
||||
columnIdentifier = Identifier.quote( columnIdentifier );
|
||||
}
|
||||
}
|
||||
else {
|
||||
final Identifier logicalTableName = database.toIdentifier(
|
||||
collector.getLogicalTableName( referencedEntity.getTable() )
|
||||
);
|
||||
|
||||
// is an intra-entity hierarchy table join so copy the name by default
|
||||
columnIdentifier = implicitNamingStrategy.determinePrimaryKeyJoinColumnName(
|
||||
new ImplicitPrimaryKeyJoinColumnNameSource() {
|
||||
@Override
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return AnnotatedJoinColumn.this.getBuildingContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedTableName() {
|
||||
return logicalTableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedPrimaryKeyColumnName() {
|
||||
return database.toIdentifier( logicalReferencedColumn );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if ( !columnIdentifier.isQuoted() && ( isRefColumnQuoted || logicalTableName.isQuoted() ) ) {
|
||||
columnIdentifier = Identifier.quote( columnIdentifier );
|
||||
}
|
||||
}
|
||||
|
||||
return physicalNamingStrategy.toPhysicalColumnName( columnIdentifier, database.getJdbcEnvironment() )
|
||||
.render( database.getJdbcEnvironment().getDialect() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this is not a column-level setting, so it's better to
|
||||
* do this work somewhere else
|
||||
*/
|
||||
@Deprecated
|
||||
private ImplicitJoinColumnNameSource.Nature getImplicitNature() {
|
||||
if ( getPropertyHolder().isEntity() ) {
|
||||
return ImplicitJoinColumnNameSource.Nature.ENTITY;
|
||||
}
|
||||
else if ( JPA2ElementCollection ) {
|
||||
return ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION;
|
||||
}
|
||||
else {
|
||||
return ImplicitJoinColumnNameSource.Nature.ENTITY_COLLECTION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* used for mappedBy cases
|
||||
*/
|
||||
|
@ -749,7 +359,8 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
initMappingColumn(
|
||||
//column.getName(),
|
||||
column.getQuotedName(),
|
||||
null, column.getLength(),
|
||||
null,
|
||||
column.getLength(),
|
||||
column.getPrecision(),
|
||||
column.getScale(),
|
||||
getMappingColumn().isNullable(),
|
||||
|
@ -762,15 +373,15 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
|
||||
@Override
|
||||
protected void addColumnBinding(SimpleValue value) {
|
||||
if ( isEmpty( mappedBy ) ) {
|
||||
if ( isEmpty( parent.getMappedBy() ) ) {
|
||||
// was the column explicitly quoted in the mapping/annotation
|
||||
// TODO: in metamodel, we need to better split global quoting and explicit quoting w/ respect to logical names
|
||||
boolean isLogicalColumnQuoted = StringHelper.isQuoted( getLogicalColumnName() );
|
||||
final ObjectNameNormalizer nameNormalizer = getBuildingContext().getObjectNameNormalizer();
|
||||
final String logicalColumnName = nameNormalizer.normalizeIdentifierQuotingAsString( getLogicalColumnName() );
|
||||
final String referencedColumn = nameNormalizer.normalizeIdentifierQuotingAsString( getReferencedColumn() );
|
||||
final String unquotedLogColName = StringHelper.unquote( logicalColumnName );
|
||||
final String unquotedRefColumn = StringHelper.unquote( referencedColumn );
|
||||
boolean isLogicalColumnQuoted = isQuoted( getLogicalColumnName() );
|
||||
final ObjectNameNormalizer normalizer = getBuildingContext().getObjectNameNormalizer();
|
||||
final String logicalColumnName = normalizer.normalizeIdentifierQuotingAsString( getLogicalColumnName() );
|
||||
final String referencedColumn = normalizer.normalizeIdentifierQuotingAsString( getReferencedColumn() );
|
||||
final String unquotedLogColName = unquote( logicalColumnName );
|
||||
final String unquotedRefColumn = unquote( referencedColumn );
|
||||
final String collectionColName = isNotEmpty( unquotedLogColName )
|
||||
? unquotedLogColName
|
||||
: getPropertyName() + '_' + unquotedRefColumn;
|
||||
|
@ -793,18 +404,20 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
public static final int NON_PK_REFERENCE = 2;
|
||||
|
||||
public static int checkReferencedColumnsType(
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
PersistentClass referencedEntity,
|
||||
MetadataBuildingContext context) {
|
||||
if ( joinColumns.length == 0 ) {
|
||||
final AnnotatedJoinColumn[] columns = joinColumns.getColumns();
|
||||
if ( columns.length == 0 ) {
|
||||
return NO_REFERENCE; //shortcut
|
||||
}
|
||||
|
||||
final Object columnOwner = findReferencedColumnOwner( referencedEntity, joinColumns[0], context );
|
||||
final AnnotatedJoinColumn firstColumn = columns[0];
|
||||
final Object columnOwner = findReferencedColumnOwner( referencedEntity, firstColumn, context );
|
||||
if ( columnOwner == null ) {
|
||||
try {
|
||||
throw new MappingException( "A '@JoinColumn' references a column named '"
|
||||
+ joinColumns[0].getReferencedColumn() + "' but the target entity '"
|
||||
+ firstColumn.getReferencedColumn() + "' but the target entity '"
|
||||
+ referencedEntity.getEntityName() + "' has no property which maps to this column" );
|
||||
}
|
||||
catch (MappingException me) {
|
||||
|
@ -817,7 +430,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
final Table table = getTable( columnOwner );
|
||||
final List<Selectable> keyColumns = referencedEntity.getKey().getSelectables();
|
||||
boolean explicitColumnReference = false;
|
||||
for ( AnnotatedJoinColumn column : joinColumns ) {
|
||||
for ( AnnotatedJoinColumn column : columns ) {
|
||||
if ( !column.isReferenceImplicit() ) {
|
||||
explicitColumnReference = true;
|
||||
if ( !keyColumns.contains( column( context, table, column.getReferencedColumn() ) ) ) {
|
||||
|
@ -828,7 +441,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
}
|
||||
if ( explicitColumnReference ) {
|
||||
// if we got to here, all the columns belong to the PK
|
||||
return keyColumns.size() == joinColumns.length
|
||||
return keyColumns.size() == columns.length
|
||||
// we have all the PK columns
|
||||
? PK_REFERENCE
|
||||
// we have a subset of the PK columns
|
||||
|
@ -862,7 +475,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
* @param column the referenced column.
|
||||
*/
|
||||
public void overrideFromReferencedColumnIfNecessary(Column column) {
|
||||
Column mappingColumn = getMappingColumn();
|
||||
final Column mappingColumn = getMappingColumn();
|
||||
if ( mappingColumn != null ) {
|
||||
// columnDefinition can also be specified using @JoinColumn, hence we have to check
|
||||
// whether it is set or not
|
||||
|
@ -883,50 +496,44 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
super.redefineColumnName( columnName, null, applyNamingStrategy );
|
||||
}
|
||||
|
||||
public static AnnotatedJoinColumn[] buildJoinTableJoinColumns(
|
||||
JoinColumn[] joinColumns,
|
||||
static AnnotatedJoinColumn buildImplicitJoinTableJoinColumn(
|
||||
Map<String, Join> secondaryTables,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
String mappedBy,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
if ( joinColumns == null ) {
|
||||
final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setImplicit( true );
|
||||
column.setNullable( false ); //I break the spec, but it's for good
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
column.setJoins( secondaryTables );
|
||||
column.setBuildingContext( buildingContext );
|
||||
column.setMappedBy( mappedBy );
|
||||
column.bind();
|
||||
return new AnnotatedJoinColumn[] { column };
|
||||
}
|
||||
else {
|
||||
final AnnotatedJoinColumn[] columns = new AnnotatedJoinColumn[joinColumns.length];
|
||||
int length = joinColumns.length;
|
||||
for (int index = 0; index < length; index++) {
|
||||
final JoinColumn joinColumn = joinColumns[index];
|
||||
final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setImplicit( true );
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
column.setJoins( secondaryTables );
|
||||
column.setBuildingContext( buildingContext );
|
||||
column.setMappedBy( mappedBy );
|
||||
column.setJoinAnnotation( joinColumn, propertyName );
|
||||
column.setNullable( false ); //I break the spec, but it's for good
|
||||
//done after the annotation to override it
|
||||
column.bind();
|
||||
columns[index] = column;
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
MetadataBuildingContext context) {
|
||||
final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setImplicit( true );
|
||||
column.setNullable( false ); //I break the spec, but it's for good
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
column.setJoins( secondaryTables );
|
||||
column.setBuildingContext( context );
|
||||
column.bind();
|
||||
return column;
|
||||
}
|
||||
|
||||
static AnnotatedJoinColumn buildExplicitJoinTableJoinColumn(
|
||||
Map<String, Join> secondaryTables,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
MetadataBuildingContext context,
|
||||
JoinColumn joinColumn) {
|
||||
final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setImplicit( true );
|
||||
column.setPropertyHolder(propertyHolder);
|
||||
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
column.setJoins( secondaryTables );
|
||||
column.setBuildingContext( context );
|
||||
column.setJoinAnnotation( joinColumn, propertyName );
|
||||
column.setNullable( false ); //I break the spec, but it's for good
|
||||
//done after the annotation to override it
|
||||
column.bind();
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder string = new StringBuilder();
|
||||
final StringBuilder string = new StringBuilder();
|
||||
string.append( getClass().getSimpleName() ).append( "(" );
|
||||
if ( isNotEmpty( getLogicalColumnName() ) ) {
|
||||
string.append( "column='" ).append( getLogicalColumnName() ).append( "'," );
|
||||
|
@ -940,4 +547,8 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
string.append( ")" );
|
||||
return string.toString();
|
||||
}
|
||||
|
||||
public void setParent(AnnotatedJoinColumns parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,581 @@
|
|||
package org.hibernate.cfg;
|
||||
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.JoinColumnOrFormula;
|
||||
import org.hibernate.annotations.JoinFormula;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.boot.model.naming.EntityNaming;
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.boot.model.naming.ImplicitJoinColumnNameSource;
|
||||
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
||||
import org.hibernate.boot.model.naming.ImplicitPrimaryKeyJoinColumnNameSource;
|
||||
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.source.spi.AttributePath;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.MetadataBuildingOptions;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Join;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hibernate.cfg.BinderHelper.getRelativePath;
|
||||
import static org.hibernate.cfg.BinderHelper.isEmptyOrNullAnnotationValue;
|
||||
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
|
||||
import static org.hibernate.internal.util.StringHelper.isQuoted;
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
|
||||
/**
|
||||
* A list of {@link jakarta.persistence.JoinColumn}s that form a single join
|
||||
* condition, similar in concept to {@link jakarta.persistence.JoinColumns},
|
||||
* but not every instance of this class corresponds to an explicit annotation
|
||||
* in the Java code.
|
||||
* <p>
|
||||
* There's no exact analog of this class in the mapping model, so some
|
||||
* information is lost when it's transformed into a list of {@link Column}s.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class AnnotatedJoinColumns {
|
||||
|
||||
private AnnotatedJoinColumn[] columns;
|
||||
private PropertyHolder propertyHolder;
|
||||
private String propertyName; // this is really a .-separated property path
|
||||
private MetadataBuildingContext buildingContext;
|
||||
|
||||
//TODO: do we really need to hang so many strings off this class?
|
||||
private String mappedBy;
|
||||
private String mappedByPropertyName; //property name on the owning side if any
|
||||
private String mappedByTableName; //table name on the mapped by side if any
|
||||
private String mappedByEntityName;
|
||||
private boolean elementCollection;
|
||||
private String manyToManyOwnerSideEntityName;
|
||||
|
||||
public AnnotatedJoinColumns() {}
|
||||
|
||||
public static AnnotatedJoinColumns buildJoinColumnsOrFormulas(
|
||||
JoinColumnOrFormula[] joinColumnOrFormulas,
|
||||
String mappedBy,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
MetadataBuildingContext context) {
|
||||
final AnnotatedJoinColumn[] columns = new AnnotatedJoinColumn[joinColumnOrFormulas.length];
|
||||
for ( int i = 0; i < joinColumnOrFormulas.length; i++ ) {
|
||||
final JoinColumnOrFormula columnOrFormula = joinColumnOrFormulas[i];
|
||||
final JoinFormula formula = columnOrFormula.formula();
|
||||
final JoinColumn column = columnOrFormula.column();
|
||||
columns[i] = formula.value() != null && !formula.value().isEmpty()
|
||||
? AnnotatedJoinColumn.buildJoinFormula( formula, joins, propertyHolder, propertyName, context )
|
||||
: AnnotatedJoinColumn.buildJoinColumn( column, mappedBy, joins, propertyHolder, propertyName, context );
|
||||
}
|
||||
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
|
||||
joinColumns.setBuildingContext( context );
|
||||
joinColumns.setPropertyHolder( propertyHolder );
|
||||
joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
joinColumns.setColumns( columns );
|
||||
joinColumns.setMappedBy( mappedBy );
|
||||
return joinColumns;
|
||||
}
|
||||
|
||||
public static AnnotatedJoinColumns buildJoinColumns(
|
||||
JoinColumn[] joinColumns,
|
||||
Comment comment,
|
||||
String mappedBy,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
return buildJoinColumnsWithDefaultColumnSuffix(
|
||||
joinColumns,
|
||||
comment,
|
||||
mappedBy,
|
||||
joins,
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
"",
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
public static AnnotatedJoinColumns buildJoinColumnsWithDefaultColumnSuffix(
|
||||
JoinColumn[] joinColumns,
|
||||
Comment comment,
|
||||
String mappedBy,
|
||||
Map<String, Join> joins,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
String defaultColumnSuffix,
|
||||
MetadataBuildingContext context) {
|
||||
final String path = qualify( propertyHolder.getPath(), propertyName );
|
||||
final JoinColumn[] overriddes = propertyHolder.getOverriddenJoinColumn( path );
|
||||
final JoinColumn[] actualColumns = overriddes == null ? joinColumns : overriddes;
|
||||
if ( actualColumns == null || actualColumns.length == 0 ) {
|
||||
final AnnotatedJoinColumn joinColumn = AnnotatedJoinColumn.buildJoinColumn(
|
||||
null,
|
||||
comment,
|
||||
mappedBy,
|
||||
joins,
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
defaultColumnSuffix,
|
||||
context
|
||||
);
|
||||
final AnnotatedJoinColumns annotatedJoinColumns = new AnnotatedJoinColumns();
|
||||
annotatedJoinColumns.setBuildingContext( context );
|
||||
annotatedJoinColumns.setPropertyHolder( propertyHolder );
|
||||
annotatedJoinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
annotatedJoinColumns.setColumns( new AnnotatedJoinColumn[] { joinColumn } );
|
||||
annotatedJoinColumns.setMappedBy( mappedBy );
|
||||
return annotatedJoinColumns;
|
||||
}
|
||||
else {
|
||||
final AnnotatedJoinColumn[] result = new AnnotatedJoinColumn[actualColumns.length];
|
||||
for ( int index = 0; index < actualColumns.length; index++ ) {
|
||||
result[index] = AnnotatedJoinColumn.buildJoinColumn(
|
||||
actualColumns[index],
|
||||
comment,
|
||||
mappedBy,
|
||||
joins,
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
defaultColumnSuffix,
|
||||
context
|
||||
);
|
||||
}
|
||||
final AnnotatedJoinColumns annotatedJoinColumns = new AnnotatedJoinColumns();
|
||||
annotatedJoinColumns.setBuildingContext( context );
|
||||
annotatedJoinColumns.setPropertyHolder( propertyHolder );
|
||||
annotatedJoinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
annotatedJoinColumns.setColumns( result );
|
||||
annotatedJoinColumns.setMappedBy( mappedBy );
|
||||
return annotatedJoinColumns;
|
||||
}
|
||||
}
|
||||
|
||||
public static AnnotatedJoinColumns buildJoinTableJoinColumns(
|
||||
JoinColumn[] joinColumns,
|
||||
Map<String, Join> secondaryTables,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
String mappedBy,
|
||||
MetadataBuildingContext context) {
|
||||
final AnnotatedJoinColumn[] columns;
|
||||
if ( joinColumns == null ) {
|
||||
columns = new AnnotatedJoinColumn[] { AnnotatedJoinColumn.buildImplicitJoinTableJoinColumn(
|
||||
secondaryTables,
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
context
|
||||
) };
|
||||
}
|
||||
else {
|
||||
columns = new AnnotatedJoinColumn[joinColumns.length];
|
||||
int length = joinColumns.length;
|
||||
for (int index = 0; index < length; index++) {
|
||||
columns[index] = AnnotatedJoinColumn.buildExplicitJoinTableJoinColumn(
|
||||
secondaryTables,
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
context,
|
||||
joinColumns[index]
|
||||
);
|
||||
}
|
||||
}
|
||||
final AnnotatedJoinColumns annotatedJoinColumns = new AnnotatedJoinColumns();
|
||||
annotatedJoinColumns.setBuildingContext( context );
|
||||
annotatedJoinColumns.setPropertyHolder( propertyHolder );
|
||||
annotatedJoinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
annotatedJoinColumns.setColumns( columns );
|
||||
annotatedJoinColumns.setMappedBy( mappedBy );
|
||||
return annotatedJoinColumns;
|
||||
}
|
||||
|
||||
public AnnotatedJoinColumn[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public void setColumns(AnnotatedJoinColumn[] columns) {
|
||||
this.columns = columns;
|
||||
if ( columns != null ) {
|
||||
for ( AnnotatedJoinColumn column : columns ) {
|
||||
column.setParent( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getMappedBy() {
|
||||
return mappedBy;
|
||||
}
|
||||
|
||||
public void setMappedBy(String mappedBy) {
|
||||
this.mappedBy = mappedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the association mapping annotation did specify
|
||||
* {@link jakarta.persistence.OneToMany#mappedBy() mappedBy},
|
||||
* meaning that this {@code @JoinColumn} mapping belongs to an
|
||||
* unowned many-valued association.
|
||||
*/
|
||||
public boolean hasMappedBy() {
|
||||
return !isEmptyOrNullAnnotationValue( getMappedBy() );
|
||||
}
|
||||
|
||||
public String getMappedByEntityName() {
|
||||
return mappedByEntityName;
|
||||
}
|
||||
|
||||
public String getMappedByPropertyName() {
|
||||
return mappedByPropertyName;
|
||||
}
|
||||
|
||||
public String getMappedByTableName() {
|
||||
return mappedByTableName;
|
||||
}
|
||||
|
||||
public PropertyHolder getPropertyHolder() {
|
||||
return propertyHolder;
|
||||
}
|
||||
|
||||
public void setPropertyHolder(PropertyHolder propertyHolder) {
|
||||
this.propertyHolder = propertyHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override persistent class on oneToMany Cases for late settings
|
||||
* Must only be used on second level pass binding
|
||||
*/
|
||||
public void setPersistentClass(
|
||||
PersistentClass persistentClass,
|
||||
Map<String, Join> joins,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
// TODO shouldn't we deduce the class name from the persistentClass?
|
||||
propertyHolder = buildPropertyHolder(
|
||||
persistentClass,
|
||||
joins,
|
||||
buildingContext,
|
||||
inheritanceStatePerClass
|
||||
);
|
||||
for ( AnnotatedJoinColumn column : columns ) {
|
||||
column.setPropertyHolder( propertyHolder );
|
||||
}
|
||||
}
|
||||
|
||||
public void setBuildingContext(MetadataBuildingContext buildingContext) {
|
||||
this.buildingContext = buildingContext;
|
||||
}
|
||||
|
||||
public boolean isElementCollection() {
|
||||
return elementCollection;
|
||||
}
|
||||
|
||||
public void setElementCollection(boolean elementCollection) {
|
||||
this.elementCollection = elementCollection;
|
||||
}
|
||||
|
||||
public void setManyToManyOwnerSideEntityName(String entityName) {
|
||||
manyToManyOwnerSideEntityName = entityName;
|
||||
}
|
||||
|
||||
public String getManyToManyOwnerSideEntityName() {
|
||||
return manyToManyOwnerSideEntityName;
|
||||
}
|
||||
|
||||
public void setMappedBy(String entityName, String logicalTableName, String mappedByProperty) {
|
||||
mappedByEntityName = entityName;
|
||||
mappedByTableName = logicalTableName;
|
||||
mappedByPropertyName = mappedByProperty;
|
||||
}
|
||||
|
||||
String buildDefaultColumnName(PersistentClass referencedEntity, String logicalReferencedColumn) {
|
||||
final MetadataBuildingOptions options = buildingContext.getBuildingOptions();
|
||||
final ImplicitNamingStrategy implicitNamingStrategy = options.getImplicitNamingStrategy();
|
||||
final PhysicalNamingStrategy physicalNamingStrategy = options.getPhysicalNamingStrategy();
|
||||
|
||||
boolean mappedBySide = getMappedByTableName() != null || getMappedByPropertyName() != null;
|
||||
boolean ownerSide = getPropertyName() != null;
|
||||
boolean isRefColumnQuoted = isQuoted( logicalReferencedColumn );
|
||||
|
||||
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
|
||||
final Database database = collector.getDatabase();
|
||||
|
||||
Identifier columnIdentifier;
|
||||
if ( mappedBySide ) {
|
||||
// NOTE : While it is completely misleading here to allow for the combination
|
||||
// of a "JPA ElementCollection" to be mappedBy, the code that uses this
|
||||
// class relies on this behavior for handling the inverse side of
|
||||
// many-to-many mappings
|
||||
columnIdentifier = implicitNamingStrategy.determineJoinColumnName(
|
||||
new UnownedImplicitJoinColumnNameSource( referencedEntity, logicalReferencedColumn )
|
||||
);
|
||||
|
||||
//one element was quoted so we quote
|
||||
if ( isRefColumnQuoted || isQuoted( getMappedByTableName() ) ) {
|
||||
columnIdentifier = Identifier.quote( columnIdentifier );
|
||||
}
|
||||
}
|
||||
else if ( ownerSide ) {
|
||||
final String logicalTableName = collector.getLogicalTableName( referencedEntity.getTable() );
|
||||
|
||||
columnIdentifier = implicitNamingStrategy.determineJoinColumnName(
|
||||
new OwnedImplicitJoinColumnNameSource( referencedEntity, logicalTableName, logicalReferencedColumn )
|
||||
);
|
||||
|
||||
// HHH-11826 magic. See Ejb3Column and the HHH-6005 comments
|
||||
if ( columnIdentifier.getText().contains( "_collection&&element_" ) ) {
|
||||
columnIdentifier = Identifier.toIdentifier(
|
||||
columnIdentifier.getText().replace( "_collection&&element_", "_" ),
|
||||
columnIdentifier.isQuoted()
|
||||
);
|
||||
}
|
||||
|
||||
//one element was quoted so we quote
|
||||
if ( isRefColumnQuoted || isQuoted( logicalTableName ) ) {
|
||||
columnIdentifier = Identifier.quote( columnIdentifier );
|
||||
}
|
||||
}
|
||||
else {
|
||||
final Identifier logicalTableName = database.toIdentifier(
|
||||
collector.getLogicalTableName( referencedEntity.getTable() )
|
||||
);
|
||||
|
||||
// is an intra-entity hierarchy table join so copy the name by default
|
||||
columnIdentifier = implicitNamingStrategy.determinePrimaryKeyJoinColumnName(
|
||||
new ImplicitPrimaryKeyJoinColumnNameSource() {
|
||||
@Override
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return buildingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedTableName() {
|
||||
return logicalTableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedPrimaryKeyColumnName() {
|
||||
return database.toIdentifier( logicalReferencedColumn );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if ( !columnIdentifier.isQuoted() && ( isRefColumnQuoted || logicalTableName.isQuoted() ) ) {
|
||||
columnIdentifier = Identifier.quote( columnIdentifier );
|
||||
}
|
||||
}
|
||||
|
||||
final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment();
|
||||
return physicalNamingStrategy.toPhysicalColumnName( columnIdentifier, jdbcEnvironment )
|
||||
.render( jdbcEnvironment.getDialect() );
|
||||
}
|
||||
|
||||
/**
|
||||
* A property path relative to the {@link #getPropertyHolder() PropertyHolder}.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public void setPropertyName(String propertyName) {
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
private ImplicitJoinColumnNameSource.Nature getImplicitNature() {
|
||||
if ( getPropertyHolder().isEntity() ) {
|
||||
return ImplicitJoinColumnNameSource.Nature.ENTITY;
|
||||
}
|
||||
else if ( isElementCollection() ) {
|
||||
return ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION;
|
||||
}
|
||||
else {
|
||||
return ImplicitJoinColumnNameSource.Nature.ENTITY_COLLECTION;
|
||||
}
|
||||
}
|
||||
|
||||
private class UnownedImplicitJoinColumnNameSource implements ImplicitJoinColumnNameSource {
|
||||
final AttributePath attributePath;
|
||||
final Nature implicitNamingNature;
|
||||
|
||||
private final EntityNaming entityNaming;
|
||||
|
||||
private final Identifier referencedTableName;
|
||||
private final String logicalReferencedColumn;
|
||||
|
||||
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
|
||||
final Database database = collector.getDatabase();
|
||||
|
||||
public UnownedImplicitJoinColumnNameSource(PersistentClass referencedEntity, String logicalReferencedColumn) {
|
||||
this.logicalReferencedColumn = logicalReferencedColumn;
|
||||
attributePath = AttributePath.parse( getMappedByPropertyName() );
|
||||
implicitNamingNature = getImplicitNature();
|
||||
entityNaming = new EntityNaming() {
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return referencedEntity.getClassName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityName() {
|
||||
return referencedEntity.getEntityName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJpaEntityName() {
|
||||
return referencedEntity.getJpaEntityName();
|
||||
}
|
||||
};
|
||||
referencedTableName = database.toIdentifier( getMappedByTableName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return implicitNamingNature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityNaming getEntityNaming() {
|
||||
return entityNaming;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributePath getAttributePath() {
|
||||
return attributePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedTableName() {
|
||||
return referencedTableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedColumnName() {
|
||||
if ( logicalReferencedColumn != null ) {
|
||||
return database.toIdentifier(logicalReferencedColumn);
|
||||
}
|
||||
|
||||
if ( getMappedByEntityName() == null || getMappedByPropertyName() == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Property mappedByProperty = collector.getEntityBinding( getMappedByEntityName() )
|
||||
.getProperty( getMappedByPropertyName() );
|
||||
final SimpleValue value = (SimpleValue) mappedByProperty.getValue();
|
||||
if ( value.getSelectables().isEmpty() ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"Association '%s' is 'mappedBy' a property '%s' of entity '%s' with no columns",
|
||||
propertyHolder.getPath(),
|
||||
getMappedByPropertyName(),
|
||||
getMappedByEntityName()
|
||||
)
|
||||
);
|
||||
}
|
||||
final Selectable selectable = value.getSelectables().get(0);
|
||||
if ( !(selectable instanceof Column) ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"Association '%s' is 'mappedBy' a property '%s' of entity '%s' which maps to a formula",
|
||||
propertyHolder.getPath(),
|
||||
getMappedByPropertyName(),
|
||||
propertyHolder.getPath()
|
||||
)
|
||||
);
|
||||
}
|
||||
if ( value.getSelectables().size()>1 ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"Association '%s' is 'mappedBy' a property '%s' of entity '%s' with multiple columns",
|
||||
propertyHolder.getPath(),
|
||||
getMappedByPropertyName(),
|
||||
propertyHolder.getPath()
|
||||
)
|
||||
);
|
||||
}
|
||||
return database.toIdentifier( ( (Column) selectable ).getQuotedName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return buildingContext;
|
||||
}
|
||||
}
|
||||
|
||||
private class OwnedImplicitJoinColumnNameSource implements ImplicitJoinColumnNameSource {
|
||||
final Nature implicitNamingNature;
|
||||
|
||||
private final EntityNaming entityNaming;
|
||||
|
||||
private final AttributePath attributePath;
|
||||
private final Identifier referencedTableName;
|
||||
private final Identifier referencedColumnName;
|
||||
|
||||
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
|
||||
final Database database = collector.getDatabase();
|
||||
|
||||
public OwnedImplicitJoinColumnNameSource(PersistentClass referencedEntity, String logicalTableName, String logicalReferencedColumn) {
|
||||
implicitNamingNature = getImplicitNature();
|
||||
entityNaming = new EntityNaming() {
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return referencedEntity.getClassName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityName() {
|
||||
return referencedEntity.getEntityName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJpaEntityName() {
|
||||
return referencedEntity.getJpaEntityName();
|
||||
}
|
||||
};
|
||||
attributePath = AttributePath.parse( getPropertyName() );
|
||||
referencedTableName = database.toIdentifier( logicalTableName );
|
||||
referencedColumnName = database.toIdentifier( logicalReferencedColumn );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return implicitNamingNature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityNaming getEntityNaming() {
|
||||
return entityNaming;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributePath getAttributePath() {
|
||||
return attributePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedTableName() {
|
||||
return referencedTableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getReferencedColumnName() {
|
||||
return referencedColumnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return buildingContext;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -152,6 +152,7 @@ import static org.hibernate.cfg.BinderHelper.getMappedSuperclassOrNull;
|
|||
import static org.hibernate.cfg.BinderHelper.getOverridableAnnotation;
|
||||
import static org.hibernate.cfg.BinderHelper.getPath;
|
||||
import static org.hibernate.cfg.BinderHelper.getPropertyOverriddenByMapperOrMapsId;
|
||||
import static org.hibernate.cfg.BinderHelper.getRelativePath;
|
||||
import static org.hibernate.cfg.BinderHelper.hasToOneAnnotation;
|
||||
import static org.hibernate.cfg.BinderHelper.makeIdGenerator;
|
||||
import static org.hibernate.cfg.InheritanceState.getInheritanceStateOfSuperEntity;
|
||||
|
@ -1118,7 +1119,7 @@ public final class AnnotationBinder {
|
|||
context
|
||||
).extractMetadata();
|
||||
AnnotatedColumn[] columns = columnsBuilder.getColumns();
|
||||
AnnotatedJoinColumn[] joinColumns = columnsBuilder.getJoinColumns();
|
||||
AnnotatedJoinColumns joinColumns = columnsBuilder.getJoinColumns();
|
||||
|
||||
final PropertyBinder propertyBinder = new PropertyBinder();
|
||||
propertyBinder.setName( inferredData.getPropertyName() );
|
||||
|
@ -1505,7 +1506,7 @@ public final class AnnotationBinder {
|
|||
Class<? extends CompositeUserType<?>> compositeUserType) {
|
||||
final String referencedEntityName;
|
||||
final String propertyName;
|
||||
final AnnotatedJoinColumn[] actualColumns;
|
||||
final AnnotatedJoinColumns actualColumns;
|
||||
if ( isOverridden ) {
|
||||
// careful: not always a @MapsId property, sometimes it's from an @IdClass
|
||||
PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId(
|
||||
|
@ -1513,7 +1514,12 @@ public final class AnnotationBinder {
|
|||
);
|
||||
referencedEntityName = mapsIdProperty.getClassOrElementName();
|
||||
propertyName = mapsIdProperty.getPropertyName();
|
||||
actualColumns = (AnnotatedJoinColumn[]) columns;
|
||||
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
|
||||
joinColumns.setBuildingContext( context );
|
||||
joinColumns.setPropertyHolder( propertyHolder );
|
||||
joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
|
||||
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns );
|
||||
actualColumns = joinColumns;
|
||||
}
|
||||
else {
|
||||
referencedEntityName = null;
|
||||
|
@ -1553,7 +1559,7 @@ public final class AnnotationBinder {
|
|||
boolean isIdentifierMapper,
|
||||
MetadataBuildingContext context,
|
||||
XProperty property,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
boolean forcePersist) {
|
||||
|
||||
//check validity
|
||||
|
@ -1573,12 +1579,12 @@ public final class AnnotationBinder {
|
|||
JoinTable assocTable = propertyHolder.getJoinTable(property);
|
||||
if ( assocTable != null ) {
|
||||
Join join = propertyHolder.addJoin( assocTable, false );
|
||||
for ( AnnotatedJoinColumn joinColumn : joinColumns) {
|
||||
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) {
|
||||
joinColumn.setExplicitTableName( join.getTable().getName() );
|
||||
}
|
||||
}
|
||||
bindAny(
|
||||
BinderHelper.getCascadeStrategy( null, hibernateCascade, false, forcePersist),
|
||||
BinderHelper.getCascadeStrategy( null, hibernateCascade, false, forcePersist ),
|
||||
//@Any has not cascade attribute
|
||||
joinColumns,
|
||||
onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action(),
|
||||
|
@ -1595,20 +1601,20 @@ public final class AnnotationBinder {
|
|||
boolean inSecondPass,
|
||||
XProperty property,
|
||||
AnnotatedColumn[] columns,
|
||||
AnnotatedJoinColumn[] joinColumns) {
|
||||
AnnotatedJoinColumns joinColumns) {
|
||||
//process indexes after everything: in second pass, many to one has to be done before indexes
|
||||
Index index = property.getAnnotation( Index.class );
|
||||
final Index index = property.getAnnotation( Index.class );
|
||||
if ( index != null ) {
|
||||
if ( joinColumns != null ) {
|
||||
|
||||
for ( AnnotatedColumn column : joinColumns) {
|
||||
for ( AnnotatedColumn column : joinColumns.getColumns() ) {
|
||||
column.addIndex( index, inSecondPass);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( columns != null ) {
|
||||
for ( AnnotatedColumn column : columns) {
|
||||
column.addIndex( index, inSecondPass);
|
||||
for ( AnnotatedColumn column : columns ) {
|
||||
column.addIndex( index, inSecondPass );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1619,23 +1625,23 @@ public final class AnnotationBinder {
|
|||
boolean inSecondPass,
|
||||
XProperty property,
|
||||
AnnotatedColumn[] columns,
|
||||
AnnotatedJoinColumn[] joinColumns) {
|
||||
AnnotatedJoinColumns joinColumns) {
|
||||
// Natural ID columns must reside in one single UniqueKey within the Table.
|
||||
// For now, simply ensure consistent naming.
|
||||
// TODO: AFAIK, there really isn't a reason for these UKs to be created
|
||||
// on the secondPass. This whole area should go away...
|
||||
NaturalId naturalIdAnn = property.getAnnotation( NaturalId.class );
|
||||
// on the SecondPass. This whole area should go away...
|
||||
final NaturalId naturalIdAnn = property.getAnnotation( NaturalId.class );
|
||||
if ( naturalIdAnn != null ) {
|
||||
if ( joinColumns != null ) {
|
||||
for ( AnnotatedColumn column : joinColumns) {
|
||||
for ( AnnotatedColumn column : joinColumns.getColumns() ) {
|
||||
String keyName = "UK_" + Constraint.hashedName( column.getTable().getName() + "_NaturalID" );
|
||||
column.addUniqueKey( keyName, inSecondPass);
|
||||
column.addUniqueKey( keyName, inSecondPass );
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ( AnnotatedColumn column : columns) {
|
||||
String keyName = "UK_" + Constraint.hashedName( column.getTable().getName() + "_NaturalID" );
|
||||
column.addUniqueKey( keyName, inSecondPass);
|
||||
column.addUniqueKey( keyName, inSecondPass );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1854,7 +1860,7 @@ public final class AnnotationBinder {
|
|||
String propertyName,
|
||||
Class<? extends EmbeddableInstantiator> customInstantiatorImpl,
|
||||
Class<? extends CompositeUserType<?>> compositeUserTypeClass,
|
||||
AnnotatedJoinColumn[] columns) {
|
||||
AnnotatedJoinColumns columns) {
|
||||
final Component component;
|
||||
if ( referencedEntityName != null ) {
|
||||
component = createComponent(
|
||||
|
@ -2201,7 +2207,7 @@ public final class AnnotationBinder {
|
|||
|
||||
private static void bindAny(
|
||||
String cascadeStrategy,
|
||||
AnnotatedJoinColumn[] columns,
|
||||
AnnotatedJoinColumns columns,
|
||||
boolean cascadeOnDelete,
|
||||
Nullability nullability,
|
||||
PropertyHolder propertyHolder,
|
||||
|
@ -2241,14 +2247,15 @@ public final class AnnotationBinder {
|
|||
binder.setUpdatable( false );
|
||||
}
|
||||
else {
|
||||
binder.setInsertable( columns[0].isInsertable() );
|
||||
binder.setUpdatable( columns[0].isUpdatable() );
|
||||
final AnnotatedJoinColumn firstColumn = columns.getColumns()[0];
|
||||
binder.setInsertable( firstColumn.isInsertable() );
|
||||
binder.setUpdatable( firstColumn.isUpdatable() );
|
||||
}
|
||||
binder.setAccessType( inferredData.getDefaultAccess() );
|
||||
binder.setCascade( cascadeStrategy );
|
||||
Property prop = binder.makeProperty();
|
||||
//composite FK columns are in the same table so its OK
|
||||
propertyHolder.addProperty( prop, columns, inferredData.getDeclaringClass() );
|
||||
propertyHolder.addProperty( prop, columns.getColumns(), inferredData.getDeclaringClass() );
|
||||
}
|
||||
|
||||
public static HashMap<String, IdentifierGeneratorDefinition> buildGenerators(
|
||||
|
|
|
@ -52,7 +52,6 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Collection;
|
||||
|
@ -84,6 +83,7 @@ import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
|||
|
||||
import static org.hibernate.cfg.AnnotatedJoinColumn.NON_PK_REFERENCE;
|
||||
import static org.hibernate.cfg.AnnotatedJoinColumn.checkReferencedColumnsType;
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
import static org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies.EMBEDDED;
|
||||
import static org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies.NOOP;
|
||||
import static org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies.interpret;
|
||||
|
@ -162,7 +162,7 @@ public class BinderHelper {
|
|||
* the synthetic {@link Component}.
|
||||
*/
|
||||
public static void createSyntheticPropertyReference(
|
||||
AnnotatedJoinColumn[] columns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
// the target entity of the association, to which the columns belong
|
||||
PersistentClass targetEntity,
|
||||
// the entity which declares the association (used for exception message)
|
||||
|
@ -172,15 +172,16 @@ public class BinderHelper {
|
|||
// true when we do the reverse side of a @ManyToMany
|
||||
boolean inverse,
|
||||
MetadataBuildingContext context) {
|
||||
final AnnotatedJoinColumn[] columns = joinColumns.getColumns();
|
||||
|
||||
// this work is not necessary for a primary key reference
|
||||
if ( checkReferencedColumnsType( columns, targetEntity, context ) == NON_PK_REFERENCE ) { // && !firstColumn.isImplicit()
|
||||
if ( checkReferencedColumnsType( joinColumns, targetEntity, context ) == NON_PK_REFERENCE ) { // && !firstColumn.isImplicit()
|
||||
// all the columns have to belong to the same table;
|
||||
// figure out which table has the columns by looking
|
||||
// for a PersistentClass or Join in the hierarchy of
|
||||
// the target entity which has the first column
|
||||
final Object columnOwner = findReferencedColumnOwner( targetEntity, columns[0], context );
|
||||
checkColumnInSameTable( columns, targetEntity, associatedEntity, context, columnOwner );
|
||||
checkColumnInSameTable( joinColumns, targetEntity, associatedEntity, context, columnOwner );
|
||||
// find all properties mapped to each column
|
||||
final List<Property> properties = findPropertiesByColumns( columnOwner, columns, associatedEntity, context );
|
||||
// create a Property along with the new synthetic
|
||||
|
@ -214,28 +215,28 @@ public class BinderHelper {
|
|||
* must return the same value for all of them.
|
||||
*/
|
||||
private static void checkColumnInSameTable(
|
||||
AnnotatedJoinColumn[] columns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
PersistentClass targetEntity,
|
||||
PersistentClass associatedEntity,
|
||||
MetadataBuildingContext context,
|
||||
Object columnOwner) {
|
||||
final AnnotatedJoinColumn firstColumn = columns[0];
|
||||
for ( AnnotatedJoinColumn column: columns) {
|
||||
if ( column.hasMappedBy() ) {
|
||||
// we should only get called for owning side of association
|
||||
throw new AssertionFailure("no need to create synthetic properties for unowned collections");
|
||||
}
|
||||
if ( joinColumns.hasMappedBy() ) {
|
||||
// we should only get called for owning side of association
|
||||
throw new AssertionFailure("no need to create synthetic properties for unowned collections");
|
||||
}
|
||||
for ( AnnotatedJoinColumn column: joinColumns.getColumns() ) {
|
||||
final Object owner = findReferencedColumnOwner( targetEntity, column, context );
|
||||
if ( owner == null ) {
|
||||
throw new AnnotationException( "A '@JoinColumn' for association "
|
||||
+ associationMessage( associatedEntity, firstColumn )
|
||||
+ associationMessage( associatedEntity, column )
|
||||
+ " references a column named '" + column.getReferencedColumn()
|
||||
+ "' which is not mapped by the target entity '"
|
||||
+ targetEntity.getEntityName() + "'" );
|
||||
}
|
||||
if ( owner != columnOwner) {
|
||||
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0];
|
||||
throw new AnnotationException( "The '@JoinColumn's for association "
|
||||
+ associationMessage( associatedEntity, firstColumn )
|
||||
+ associationMessage( associatedEntity, column )
|
||||
+ " reference columns of different tables mapped by the target entity '"
|
||||
+ targetEntity.getEntityName() + "' ('" + column.getReferencedColumn() +
|
||||
"' belongs to a different table to '" + firstColumn.getReferencedColumn() + "'" );
|
||||
|
@ -483,7 +484,7 @@ public class BinderHelper {
|
|||
// each column, but this means we will reject some mappings
|
||||
// that could be made to work for a different choice of
|
||||
// properties (it's also not very deterministic)
|
||||
List<Property> orderedProperties = new ArrayList<>();
|
||||
final List<Property> orderedProperties = new ArrayList<>();
|
||||
int lastPropertyColumnIndex = 0;
|
||||
Property currentProperty = null;
|
||||
for ( Column column : orderedColumns ) {
|
||||
|
@ -694,13 +695,12 @@ public class BinderHelper {
|
|||
if ( propertyHolder == null ) {
|
||||
return propertyName;
|
||||
}
|
||||
final String path = propertyHolder.getPath();
|
||||
final String entityName = propertyHolder.getPersistentClass().getEntityName();
|
||||
if ( path.length() == entityName.length() ) {
|
||||
return propertyName;
|
||||
}
|
||||
else {
|
||||
return StringHelper.qualify( path.substring( entityName.length() + 1 ), propertyName );
|
||||
final String path = propertyHolder.getPath();
|
||||
final String entityName = propertyHolder.getPersistentClass().getEntityName();
|
||||
return path.length() == entityName.length()
|
||||
? propertyName
|
||||
: qualify( path.substring(entityName.length() + 1), propertyName );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -708,12 +708,9 @@ public class BinderHelper {
|
|||
PersistentClass persistentClass,
|
||||
AnnotatedJoinColumn joinColumn,
|
||||
MetadataBuildingContext context) {
|
||||
if ( joinColumn.isImplicit() || joinColumn.isReferenceImplicit() ) {
|
||||
return persistentClass;
|
||||
}
|
||||
else {
|
||||
return findColumnOwner( persistentClass, joinColumn.getReferencedColumn(), context );
|
||||
}
|
||||
return joinColumn.isImplicit() || joinColumn.isReferenceImplicit()
|
||||
? persistentClass
|
||||
: findColumnOwner( persistentClass, joinColumn.getReferencedColumn(), context );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1043,7 +1040,7 @@ public class BinderHelper {
|
|||
public static Any buildAnyValue(
|
||||
jakarta.persistence.Column discriminatorColumn,
|
||||
Formula discriminatorFormula,
|
||||
AnnotatedJoinColumn[] keyColumns,
|
||||
AnnotatedJoinColumns keyColumns,
|
||||
PropertyData inferredData,
|
||||
boolean cascadeOnDelete,
|
||||
boolean lazy,
|
||||
|
@ -1053,8 +1050,9 @@ public class BinderHelper {
|
|||
boolean optional,
|
||||
MetadataBuildingContext context) {
|
||||
final XProperty xProperty = inferredData.getProperty();
|
||||
final AnnotatedJoinColumn[] columns = keyColumns.getColumns();
|
||||
|
||||
final Any value = new Any( context, keyColumns[0].getTable(), true );
|
||||
final Any value = new Any( context, columns[0].getTable(), true );
|
||||
value.setLazy( lazy );
|
||||
value.setCascadeDeleteEnabled( cascadeOnDelete );
|
||||
|
||||
|
@ -1090,7 +1088,7 @@ public class BinderHelper {
|
|||
final Map<Object,Class<?>> discriminatorValueMappings = new HashMap<>();
|
||||
processAnyDiscriminatorValues(
|
||||
inferredData.getProperty(),
|
||||
(valueMapping) -> discriminatorValueMappings.put(
|
||||
valueMapping -> discriminatorValueMappings.put(
|
||||
discriminatorJavaType.wrap( valueMapping.discriminator(), null ),
|
||||
valueMapping.entity()
|
||||
)
|
||||
|
@ -1098,12 +1096,12 @@ public class BinderHelper {
|
|||
value.setDiscriminatorValueMappings( discriminatorValueMappings );
|
||||
|
||||
BasicValueBinder keyValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ANY_KEY, context );
|
||||
assert keyColumns.length == 1;
|
||||
keyColumns[0].setTable( value.getTable() );
|
||||
keyValueBinder.setColumns( keyColumns );
|
||||
assert columns.length == 1;
|
||||
columns[0].setTable( value.getTable() );
|
||||
keyValueBinder.setColumns(columns);
|
||||
|
||||
if ( !optional ) {
|
||||
for (AnnotatedJoinColumn column : keyColumns) {
|
||||
for ( AnnotatedJoinColumn column : columns) {
|
||||
column.setNullable( false );
|
||||
}
|
||||
}
|
||||
|
@ -1112,10 +1110,10 @@ public class BinderHelper {
|
|||
value.setKey( keyDescriptor );
|
||||
keyValueBinder.fillSimpleValue();
|
||||
AnnotatedColumn.checkPropertyConsistency(
|
||||
keyColumns,
|
||||
columns,
|
||||
propertyHolder.getEntityName() + "." + inferredData.getPropertyName()
|
||||
);
|
||||
keyColumns[0].linkWithValue( keyDescriptor );
|
||||
columns[0].linkWithValue( keyDescriptor );
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -1168,7 +1166,7 @@ public class BinderHelper {
|
|||
}
|
||||
|
||||
public static String getPath(PropertyHolder holder, PropertyData property) {
|
||||
return StringHelper.qualify( holder.getPath(), property.getPropertyName() );
|
||||
return qualify( holder.getPath(), property.getPropertyName() );
|
||||
}
|
||||
|
||||
static PropertyData getPropertyOverriddenByMapperOrMapsId(
|
||||
|
|
|
@ -26,7 +26,6 @@ import org.hibernate.annotations.common.reflection.XProperty;
|
|||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.annotations.EntityBinder;
|
||||
import org.hibernate.cfg.annotations.Nullability;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import static org.hibernate.cfg.AnnotatedColumn.buildColumnFromAnnotation;
|
||||
import static org.hibernate.cfg.AnnotatedColumn.buildColumnFromNoAnnotation;
|
||||
|
@ -35,6 +34,8 @@ import static org.hibernate.cfg.AnnotatedColumn.buildFormulaFromAnnotation;
|
|||
import static org.hibernate.cfg.BinderHelper.getOverridableAnnotation;
|
||||
import static org.hibernate.cfg.BinderHelper.getPath;
|
||||
import static org.hibernate.cfg.BinderHelper.getPropertyOverriddenByMapperOrMapsId;
|
||||
import static org.hibernate.cfg.BinderHelper.getRelativePath;
|
||||
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
||||
|
||||
/**
|
||||
* Do the initial discovery of columns metadata and apply defaults.
|
||||
|
@ -52,7 +53,7 @@ class ColumnsBuilder {
|
|||
private final EntityBinder entityBinder;
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
private AnnotatedColumn[] columns;
|
||||
private AnnotatedJoinColumn[] joinColumns;
|
||||
private AnnotatedJoinColumns joinColumns;
|
||||
|
||||
public ColumnsBuilder(
|
||||
PropertyHolder propertyHolder,
|
||||
|
@ -73,7 +74,7 @@ class ColumnsBuilder {
|
|||
return columns;
|
||||
}
|
||||
|
||||
public AnnotatedJoinColumn[] getJoinColumns() {
|
||||
public AnnotatedJoinColumns getJoinColumns() {
|
||||
return joinColumns;
|
||||
}
|
||||
|
||||
|
@ -122,14 +123,14 @@ class ColumnsBuilder {
|
|||
( property.isAnnotationPresent( ManyToOne.class )
|
||||
|| property.isAnnotationPresent( OneToOne.class ) )
|
||||
) {
|
||||
joinColumns = buildDefaultJoinColumnsForXToOne( property, inferredData );
|
||||
joinColumns = buildDefaultJoinColumnsForToOne( property, inferredData );
|
||||
}
|
||||
else if ( joinColumns == null &&
|
||||
( property.isAnnotationPresent( OneToMany.class )
|
||||
|| property.isAnnotationPresent( ElementCollection.class )
|
||||
) ) {
|
||||
OneToMany oneToMany = property.getAnnotation( OneToMany.class );
|
||||
joinColumns = AnnotatedJoinColumn.buildJoinColumns(
|
||||
joinColumns = AnnotatedJoinColumns.buildJoinColumns(
|
||||
null,
|
||||
comment,
|
||||
oneToMany != null ? oneToMany.mappedBy() : "",
|
||||
|
@ -164,12 +165,18 @@ class ColumnsBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
private AnnotatedJoinColumn[] buildDefaultJoinColumnsForXToOne(XProperty property, PropertyData inferredData) {
|
||||
AnnotatedJoinColumn[] joinColumns;
|
||||
JoinTable joinTableAnn = propertyHolder.getJoinTable( property );
|
||||
Comment comment = property.getAnnotation(Comment.class);
|
||||
private AnnotatedJoinColumns buildDefaultJoinColumnsForToOne(XProperty property, PropertyData inferredData) {
|
||||
final JoinTable joinTableAnn = propertyHolder.getJoinTable( property );
|
||||
final Comment comment = property.getAnnotation(Comment.class);
|
||||
if ( joinTableAnn != null ) {
|
||||
joinColumns = AnnotatedJoinColumn.buildJoinColumns(
|
||||
if ( isEmpty( joinTableAnn.name() ) ) {
|
||||
//TODO: I don't see why this restriction makes sense (use the same defaulting rule as for many-valued)
|
||||
throw new AnnotationException(
|
||||
"Single-valued association " + getPath( propertyHolder, inferredData )
|
||||
+ " has a '@JoinTable' annotation with no explicit 'name'"
|
||||
);
|
||||
}
|
||||
return AnnotatedJoinColumns.buildJoinColumns(
|
||||
joinTableAnn.inverseJoinColumns(),
|
||||
comment,
|
||||
null,
|
||||
|
@ -178,17 +185,10 @@ class ColumnsBuilder {
|
|||
inferredData.getPropertyName(),
|
||||
buildingContext
|
||||
);
|
||||
if ( StringHelper.isEmpty( joinTableAnn.name() ) ) {
|
||||
//TODO: I don't see why this restriction makes sense (use the same defaulting rule as for many-valued)
|
||||
throw new AnnotationException(
|
||||
"Single-valued association " + getPath( propertyHolder, inferredData )
|
||||
+ " has a '@JoinTable' annotation with no explicit 'name'"
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
OneToOne oneToOneAnn = property.getAnnotation( OneToOne.class );
|
||||
joinColumns = AnnotatedJoinColumn.buildJoinColumns(
|
||||
return AnnotatedJoinColumns.buildJoinColumns(
|
||||
null,
|
||||
comment,
|
||||
oneToOneAnn != null ? oneToOneAnn.mappedBy() : null,
|
||||
|
@ -198,53 +198,63 @@ class ColumnsBuilder {
|
|||
buildingContext
|
||||
);
|
||||
}
|
||||
return joinColumns;
|
||||
}
|
||||
|
||||
private AnnotatedJoinColumn[] buildExplicitJoinColumns(XProperty property, PropertyData inferredData) {
|
||||
private AnnotatedJoinColumns buildExplicitJoinColumns(XProperty property, PropertyData inferredData) {
|
||||
// process @JoinColumns before @Columns to handle collection of entities properly
|
||||
|
||||
final JoinColumn[] joinColumnAnnotations = getJoinColumnAnnotations(property, inferredData);
|
||||
final String propertyName = inferredData.getPropertyName();
|
||||
|
||||
final JoinColumn[] joinColumnAnnotations = getJoinColumnAnnotations( property, inferredData );
|
||||
if ( joinColumnAnnotations != null ) {
|
||||
return AnnotatedJoinColumn.buildJoinColumns(
|
||||
return AnnotatedJoinColumns.buildJoinColumns(
|
||||
joinColumnAnnotations,
|
||||
property.getAnnotation( Comment.class ),
|
||||
null,
|
||||
entityBinder.getSecondaryTables(),
|
||||
propertyHolder,
|
||||
inferredData.getPropertyName(),
|
||||
propertyName,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
final JoinColumnOrFormula[] joinColumnOrFormulaAnnotations = joinColumnOrFormulaAnnotations( property, inferredData );
|
||||
if ( joinColumnOrFormulaAnnotations != null ) {
|
||||
return AnnotatedJoinColumn.buildJoinColumnsOrFormulas(
|
||||
return AnnotatedJoinColumns.buildJoinColumnsOrFormulas(
|
||||
joinColumnOrFormulaAnnotations,
|
||||
null,
|
||||
entityBinder.getSecondaryTables(),
|
||||
propertyHolder,
|
||||
inferredData.getPropertyName(),
|
||||
propertyName,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
if ( property.isAnnotationPresent( JoinFormula.class) ) {
|
||||
final JoinFormula joinFormula = getOverridableAnnotation( property, JoinFormula.class, buildingContext );
|
||||
final AnnotatedJoinColumn[] annotatedJoinColumns = new AnnotatedJoinColumn[1];
|
||||
annotatedJoinColumns[0] = AnnotatedJoinColumn.buildJoinFormula(
|
||||
joinFormula,
|
||||
entityBinder.getSecondaryTables(),
|
||||
propertyHolder,
|
||||
inferredData.getPropertyName(),
|
||||
buildingContext
|
||||
);
|
||||
return annotatedJoinColumns;
|
||||
return buildJoinColumnsWithFormula( propertyName, joinFormula );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private AnnotatedJoinColumns buildJoinColumnsWithFormula(String propertyName, JoinFormula joinFormula) {
|
||||
final AnnotatedJoinColumn[] columns = new AnnotatedJoinColumn[1];
|
||||
columns[0] = AnnotatedJoinColumn.buildJoinFormula(
|
||||
joinFormula,
|
||||
entityBinder.getSecondaryTables(),
|
||||
propertyHolder,
|
||||
propertyName,
|
||||
buildingContext
|
||||
);
|
||||
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
|
||||
joinColumns.setBuildingContext( buildingContext );
|
||||
joinColumns.setPropertyHolder( propertyHolder );
|
||||
joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName) );
|
||||
joinColumns.setColumns( columns );
|
||||
return joinColumns;
|
||||
}
|
||||
|
||||
private JoinColumnOrFormula[] joinColumnOrFormulaAnnotations(XProperty property, PropertyData inferredData) {
|
||||
if ( property.isAnnotationPresent( JoinColumnOrFormula.class ) ) {
|
||||
return new JoinColumnOrFormula[] { property.getAnnotation( JoinColumnOrFormula.class ) };
|
||||
|
@ -292,10 +302,13 @@ class ColumnsBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* useful to override a column either by @MapsId or by @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?
|
||||
private AnnotatedColumn[] buildExplicitOrDefaultJoinColumn(PropertyData overridingProperty) {
|
||||
final AnnotatedColumn[] columns = buildExplicitJoinColumns( overridingProperty.getProperty(), overridingProperty );
|
||||
return columns == null ? buildDefaultJoinColumnsForXToOne( overridingProperty.getProperty(), overridingProperty ) : columns;
|
||||
final AnnotatedJoinColumns columns = buildExplicitJoinColumns( overridingProperty.getProperty(), overridingProperty );
|
||||
return columns == null
|
||||
? buildDefaultJoinColumnsForToOne( overridingProperty.getProperty(), overridingProperty ).getColumns()
|
||||
: columns.getColumns();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,12 +39,12 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
|||
private final String propertyName;
|
||||
private final Component component;
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
private final AnnotatedJoinColumn[] joinColumns;
|
||||
private final AnnotatedJoinColumns joinColumns;
|
||||
|
||||
public CopyIdentifierComponentSecondPass(
|
||||
Component comp,
|
||||
String referencedEntityName, String propertyName,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
super( comp, joinColumns );
|
||||
this.component = comp;
|
||||
|
@ -91,8 +91,9 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
|||
|
||||
//prepare column name structure
|
||||
boolean isExplicitReference = true;
|
||||
final Map<String, AnnotatedJoinColumn> columnByReferencedName = mapOfSize( joinColumns.length );
|
||||
for ( AnnotatedJoinColumn joinColumn : joinColumns ) {
|
||||
final AnnotatedJoinColumn[] cols = joinColumns.getColumns();
|
||||
final Map<String, AnnotatedJoinColumn> columnByReferencedName = mapOfSize( cols.length );
|
||||
for ( AnnotatedJoinColumn joinColumn : cols) {
|
||||
if ( !joinColumn.isReferenceImplicit() ) {
|
||||
//JPA 2 requires referencedColumnNames to be case-insensitive
|
||||
columnByReferencedName.put( joinColumn.getReferencedColumn().toLowerCase(Locale.ROOT), joinColumn );
|
||||
|
@ -101,8 +102,8 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
|||
//try default column orientation
|
||||
if ( columnByReferencedName.isEmpty() ) {
|
||||
isExplicitReference = false;
|
||||
for ( int i = 0; i < joinColumns.length; i++ ) {
|
||||
columnByReferencedName.put( String.valueOf( i ), joinColumns[i] );
|
||||
for (int i = 0; i < cols.length; i++ ) {
|
||||
columnByReferencedName.put( String.valueOf( i ), cols[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,8 +185,9 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
|||
final SimpleValue referencedValue = (SimpleValue) referencedProperty.getValue();
|
||||
value.copyTypeFrom( referencedValue );
|
||||
|
||||
if ( joinColumns[0].isNameDeferred() ) {
|
||||
joinColumns[0].copyReferencedStructureAndCreateDefaultJoinColumns(
|
||||
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0];
|
||||
if ( firstColumn.isNameDeferred() ) {
|
||||
firstColumn.copyReferencedStructureAndCreateDefaultJoinColumns(
|
||||
referencedPersistentClass,
|
||||
referencedValue,
|
||||
value
|
||||
|
@ -200,17 +202,18 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
|||
}
|
||||
final Column column = (Column) selectable;
|
||||
final AnnotatedJoinColumn joinColumn;
|
||||
String logicalColumnName = null;
|
||||
final String logicalColumnName;
|
||||
if ( isExplicitReference ) {
|
||||
logicalColumnName = column.getName();
|
||||
//JPA 2 requires referencedColumnNames to be case-insensitive
|
||||
joinColumn = columnByReferencedName.get( logicalColumnName.toLowerCase(Locale.ROOT ) );
|
||||
}
|
||||
else {
|
||||
logicalColumnName = null;
|
||||
joinColumn = columnByReferencedName.get( String.valueOf( index.get() ) );
|
||||
index.getAndIncrement();
|
||||
}
|
||||
if ( joinColumn == null && !joinColumns[0].isNameDeferred() ) {
|
||||
if ( joinColumn == null && !firstColumn.isNameDeferred() ) {
|
||||
throw new AnnotationException(
|
||||
"Property '" + propertyName
|
||||
+ "' of entity '" + component.getOwner().getEntityName()
|
||||
|
@ -225,7 +228,7 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
|||
final Database database = buildingContext.getMetadataCollector().getDatabase();
|
||||
final PhysicalNamingStrategy physicalNamingStrategy = buildingContext.getBuildingOptions().getPhysicalNamingStrategy();
|
||||
final Identifier explicitName = database.toIdentifier( columnName );
|
||||
final Identifier physicalName = physicalNamingStrategy.toPhysicalColumnName( explicitName, database.getJdbcEnvironment() );
|
||||
final Identifier physicalName = physicalNamingStrategy.toPhysicalColumnName( explicitName, database.getJdbcEnvironment() );
|
||||
value.addColumn( new Column( physicalName.render( database.getDialect() ) ) );
|
||||
if ( joinColumn != null ) {
|
||||
applyComponentColumnSizeValueToJoinColumn( column, joinColumn );
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.hibernate.mapping.Value;
|
|||
*/
|
||||
public abstract class FkSecondPass implements SecondPass {
|
||||
protected SimpleValue value;
|
||||
protected AnnotatedJoinColumn[] columns;
|
||||
protected AnnotatedJoinColumns columns;
|
||||
/**
|
||||
* unique counter is needed to differentiate 2 instances of FKSecondPass
|
||||
* as they are compared.
|
||||
|
@ -25,7 +25,7 @@ public abstract class FkSecondPass implements SecondPass {
|
|||
private final int uniqueCounter;
|
||||
private static final AtomicInteger globalCounter = new AtomicInteger();
|
||||
|
||||
public FkSecondPass(SimpleValue value, AnnotatedJoinColumn[] columns) {
|
||||
public FkSecondPass(SimpleValue value, AnnotatedJoinColumns columns) {
|
||||
this.value = value;
|
||||
this.columns = columns;
|
||||
this.uniqueCounter = globalCounter.getAndIncrement();
|
||||
|
|
|
@ -24,7 +24,7 @@ public class JoinedSubclassFkSecondPass extends FkSecondPass {
|
|||
|
||||
public JoinedSubclassFkSecondPass(
|
||||
JoinedSubclass entity,
|
||||
AnnotatedJoinColumn[] inheritanceJoinedColumns,
|
||||
AnnotatedJoinColumns inheritanceJoinedColumns,
|
||||
SimpleValue key,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
super( key, inheritanceJoinedColumns );
|
||||
|
|
|
@ -53,7 +53,7 @@ public class OneToOneSecondPass implements SecondPass {
|
|||
private final boolean cascadeOnDelete;
|
||||
private final boolean optional;
|
||||
private final String cascadeStrategy;
|
||||
private final AnnotatedJoinColumn[] joinColumns;
|
||||
private final AnnotatedJoinColumns joinColumns;
|
||||
|
||||
//that sucks, we should read that from the property mainly
|
||||
public OneToOneSecondPass(
|
||||
|
@ -67,7 +67,7 @@ public class OneToOneSecondPass implements SecondPass {
|
|||
boolean cascadeOnDelete,
|
||||
boolean optional,
|
||||
String cascadeStrategy,
|
||||
AnnotatedJoinColumn[] columns,
|
||||
AnnotatedJoinColumns columns,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
this.ownerEntity = ownerEntity;
|
||||
this.ownerProperty = ownerProperty;
|
||||
|
|
|
@ -18,10 +18,10 @@ import org.hibernate.mapping.SimpleValue;
|
|||
*/
|
||||
public class PkDrivenByDefaultMapsIdSecondPass extends FkSecondPass {
|
||||
private final String referencedEntityName;
|
||||
private final AnnotatedJoinColumn[] columns;
|
||||
private final AnnotatedJoinColumns columns;
|
||||
private final SimpleValue value;
|
||||
|
||||
public PkDrivenByDefaultMapsIdSecondPass(String referencedEntityName, AnnotatedJoinColumn[] columns, SimpleValue value) {
|
||||
public PkDrivenByDefaultMapsIdSecondPass(String referencedEntityName, AnnotatedJoinColumns columns, SimpleValue value) {
|
||||
super( value, columns );
|
||||
this.referencedEntityName = referencedEntityName;
|
||||
this.columns = columns;
|
||||
|
|
|
@ -69,7 +69,7 @@ public class ToOneBinder {
|
|||
boolean inSecondPass,
|
||||
MetadataBuildingContext context,
|
||||
XProperty property,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
PropertyBinder propertyBinder,
|
||||
boolean forcePersist) {
|
||||
final ManyToOne manyToOne = property.getAnnotation( ManyToOne.class );
|
||||
|
@ -91,7 +91,7 @@ public class ToOneBinder {
|
|||
final JoinTable joinTable = propertyHolder.getJoinTable( property );
|
||||
if ( joinTable != null ) {
|
||||
final Join join = propertyHolder.addJoin( joinTable, false );
|
||||
for ( AnnotatedJoinColumn joinColumn : joinColumns ) {
|
||||
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) {
|
||||
joinColumn.setExplicitTableName( join.getTable().getName() );
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ public class ToOneBinder {
|
|||
|
||||
private static void bindManyToOne(
|
||||
String cascadeStrategy,
|
||||
AnnotatedJoinColumn[] columns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
boolean optional,
|
||||
NotFoundAction notFoundAction,
|
||||
boolean cascadeOnDelete,
|
||||
|
@ -142,7 +142,7 @@ public class ToOneBinder {
|
|||
MetadataBuildingContext context) {
|
||||
// All FK columns should be in the same table
|
||||
final org.hibernate.mapping.ManyToOne value =
|
||||
new org.hibernate.mapping.ManyToOne( context, columns[0].getTable() );
|
||||
new org.hibernate.mapping.ManyToOne( context, joinColumns.getColumns()[0].getTable() );
|
||||
if ( unique ) {
|
||||
// This is a @OneToOne mapped to a physical o.h.mapping.ManyToOne
|
||||
value.markAsLogicalOneToOne();
|
||||
|
@ -155,20 +155,20 @@ public class ToOneBinder {
|
|||
value.setCascadeDeleteEnabled( cascadeOnDelete );
|
||||
//value.setLazy( fetchMode != FetchMode.JOIN );
|
||||
if ( !optional ) {
|
||||
for ( AnnotatedJoinColumn column : columns ) {
|
||||
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) {
|
||||
column.setNullable( false );
|
||||
}
|
||||
}
|
||||
|
||||
if ( property.isAnnotationPresent( MapsId.class ) ) {
|
||||
//read only
|
||||
for ( AnnotatedJoinColumn column : columns ) {
|
||||
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) {
|
||||
column.setInsertable( false );
|
||||
column.setUpdatable( false );
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasSpecjManyToOne = handleSpecjSyntax( columns, inferredData, context, property );
|
||||
boolean hasSpecjManyToOne = handleSpecjSyntax( joinColumns, inferredData, context, property );
|
||||
value.setTypeName( inferredData.getClassOrElementName() );
|
||||
final String propertyName = inferredData.getPropertyName();
|
||||
value.setTypeUsingReflection( propertyHolder.getClassName(), propertyName );
|
||||
|
@ -179,7 +179,7 @@ public class ToOneBinder {
|
|||
|
||||
final FkSecondPass secondPass = new ToOneFkSecondPass(
|
||||
value,
|
||||
columns,
|
||||
joinColumns,
|
||||
!optional && unique, //cannot have nullable and unique on certain DBs like Derby
|
||||
propertyHolder.getPersistentClass(),
|
||||
fullPath,
|
||||
|
@ -194,7 +194,7 @@ public class ToOneBinder {
|
|||
|
||||
processManyToOneProperty(
|
||||
cascadeStrategy,
|
||||
columns,
|
||||
joinColumns,
|
||||
optional,
|
||||
propertyHolder,
|
||||
inferredData,
|
||||
|
@ -208,7 +208,7 @@ public class ToOneBinder {
|
|||
}
|
||||
|
||||
private static boolean handleSpecjSyntax(
|
||||
AnnotatedJoinColumn[] columns,
|
||||
AnnotatedJoinColumns columns,
|
||||
PropertyData inferredData,
|
||||
MetadataBuildingContext context,
|
||||
XProperty property) {
|
||||
|
@ -228,7 +228,7 @@ public class ToOneBinder {
|
|||
&& joinColumn.name().equals( columnName )
|
||||
&& !property.isAnnotationPresent( MapsId.class ) ) {
|
||||
hasSpecjManyToOne = true;
|
||||
for ( AnnotatedJoinColumn column : columns) {
|
||||
for ( AnnotatedJoinColumn column : columns.getColumns() ) {
|
||||
column.setInsertable( false );
|
||||
column.setUpdatable( false );
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ public class ToOneBinder {
|
|||
|
||||
private static void processManyToOneProperty(
|
||||
String cascadeStrategy,
|
||||
AnnotatedJoinColumn[] columns,
|
||||
AnnotatedJoinColumns columns,
|
||||
boolean optional,
|
||||
PropertyHolder propertyHolder,
|
||||
PropertyData inferredData,
|
||||
|
@ -250,7 +250,7 @@ public class ToOneBinder {
|
|||
boolean hasSpecjManyToOne,
|
||||
String propertyName) {
|
||||
|
||||
checkPropertyConsistency( columns, qualify( propertyHolder.getEntityName(), propertyName ) );
|
||||
checkPropertyConsistency( columns.getColumns(), qualify( propertyHolder.getEntityName(), propertyName ) );
|
||||
|
||||
//PropertyBinder binder = new PropertyBinder();
|
||||
propertyBinder.setName( propertyName );
|
||||
|
@ -265,10 +265,11 @@ public class ToOneBinder {
|
|||
propertyBinder.setUpdatable( false );
|
||||
}
|
||||
else {
|
||||
propertyBinder.setInsertable( columns[0].isInsertable() );
|
||||
propertyBinder.setUpdatable( columns[0].isUpdatable() );
|
||||
final AnnotatedJoinColumn firstColumn = columns.getColumns()[0];
|
||||
propertyBinder.setInsertable( firstColumn.isInsertable() );
|
||||
propertyBinder.setUpdatable( firstColumn.isUpdatable() );
|
||||
}
|
||||
propertyBinder.setColumns( columns );
|
||||
propertyBinder.setColumns( columns.getColumns() );
|
||||
propertyBinder.setAccessType( inferredData.getDefaultAccess() );
|
||||
propertyBinder.setCascade( cascadeStrategy );
|
||||
propertyBinder.setProperty( property );
|
||||
|
@ -361,7 +362,7 @@ public class ToOneBinder {
|
|||
boolean inSecondPass,
|
||||
MetadataBuildingContext context,
|
||||
XProperty property,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
PropertyBinder propertyBinder,
|
||||
boolean forcePersist) {
|
||||
final OneToOne oneToOne = property.getAnnotation( OneToOne.class );
|
||||
|
@ -392,7 +393,7 @@ public class ToOneBinder {
|
|||
if ( notFoundAction != null ) {
|
||||
join.disableForeignKeyCreation();
|
||||
}
|
||||
for ( AnnotatedJoinColumn joinColumn : joinColumns) {
|
||||
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) {
|
||||
joinColumn.setExplicitTableName( join.getTable().getName() );
|
||||
}
|
||||
}
|
||||
|
@ -417,7 +418,7 @@ public class ToOneBinder {
|
|||
|
||||
private static void bindOneToOne(
|
||||
String cascadeStrategy,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
boolean optional,
|
||||
FetchMode fetchMode,
|
||||
NotFoundAction notFoundAction,
|
||||
|
@ -478,7 +479,7 @@ public class ToOneBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean isMapToPK(AnnotatedJoinColumn[] joinColumns, PropertyHolder propertyHolder, boolean trueOneToOne) {
|
||||
private static boolean isMapToPK(AnnotatedJoinColumns joinColumns, PropertyHolder propertyHolder, boolean trueOneToOne) {
|
||||
if ( trueOneToOne ) {
|
||||
return true;
|
||||
}
|
||||
|
@ -491,15 +492,16 @@ public class ToOneBinder {
|
|||
return false;
|
||||
}
|
||||
else {
|
||||
List<String> idColumnNames = new ArrayList<>();
|
||||
if ( identifier.getColumnSpan() != joinColumns.length ) {
|
||||
final List<String> idColumnNames = new ArrayList<>();
|
||||
final AnnotatedJoinColumn[] columns = joinColumns.getColumns();
|
||||
if ( identifier.getColumnSpan() != columns.length ) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
for ( org.hibernate.mapping.Column currentColumn: identifier.getColumns() ) {
|
||||
idColumnNames.add( currentColumn.getName() );
|
||||
}
|
||||
for ( AnnotatedJoinColumn col: joinColumns) {
|
||||
for ( AnnotatedJoinColumn col: columns ) {
|
||||
if ( !idColumnNames.contains( col.getMappingColumn().getName() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class ToOneFkSecondPass extends FkSecondPass {
|
|||
|
||||
public ToOneFkSecondPass(
|
||||
ToOne value,
|
||||
AnnotatedJoinColumn[] columns,
|
||||
AnnotatedJoinColumns columns,
|
||||
boolean unique,
|
||||
PersistentClass persistentClass,
|
||||
String path,
|
||||
|
@ -113,7 +113,9 @@ public class ToOneFkSecondPass extends FkSecondPass {
|
|||
);
|
||||
TableBinder.bindForeignKey( targetEntity, persistentClass, columns, manyToOne, unique, buildingContext );
|
||||
// HbmMetadataSourceProcessorImpl does this only when property-ref != null, but IMO, it makes sense event if it is null
|
||||
if ( !manyToOne.isIgnoreNotFound() ) manyToOne.createPropertyRefConstraints( persistentClasses );
|
||||
if ( !manyToOne.isIgnoreNotFound() ) {
|
||||
manyToOne.createPropertyRefConstraints( persistentClasses );
|
||||
}
|
||||
}
|
||||
else if ( value instanceof OneToOne ) {
|
||||
value.createForeignKey();
|
||||
|
|
|
@ -51,10 +51,12 @@ import org.hibernate.annotations.common.reflection.XClass;
|
|||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.model.TypeDefinition;
|
||||
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.AccessType;
|
||||
import org.hibernate.cfg.AnnotatedColumn;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumn;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumns;
|
||||
import org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass;
|
||||
import org.hibernate.cfg.SetBasicValueTypeSecondPass;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
|
@ -1122,11 +1124,15 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
}
|
||||
|
||||
public void linkWithValue() {
|
||||
if ( columns[0].isNameDeferred() && !buildingContext.getMetadataCollector().isInSecondPass() && referencedEntityName != null ) {
|
||||
buildingContext.getMetadataCollector().addSecondPass(
|
||||
new PkDrivenByDefaultMapsIdSecondPass(
|
||||
referencedEntityName, (AnnotatedJoinColumn[]) columns, basicValue
|
||||
)
|
||||
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
|
||||
if ( !collector.isInSecondPass() && columns[0].isNameDeferred() && referencedEntityName != null ) {
|
||||
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
|
||||
joinColumns.setBuildingContext( buildingContext );
|
||||
joinColumns.setPropertyHolder( columns[0].getPropertyHolder() );
|
||||
joinColumns.setPropertyName( columns[0].getPropertyName() );
|
||||
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns );
|
||||
collector.addSecondPass(
|
||||
new PkDrivenByDefaultMapsIdSecondPass( referencedEntityName, joinColumns, basicValue )
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -1139,13 +1145,9 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
public void fillSimpleValue() {
|
||||
LOG.debugf( "Starting `BasicValueBinder#fillSimpleValue` for %s", propertyName );
|
||||
|
||||
final String explicitBasicTypeName;
|
||||
if ( this.explicitBasicTypeName != null ) {
|
||||
explicitBasicTypeName = this.explicitBasicTypeName;
|
||||
}
|
||||
else {
|
||||
explicitBasicTypeName = this.timeStampVersionType;
|
||||
}
|
||||
final String explicitBasicTypeName = this.explicitBasicTypeName != null
|
||||
? this.explicitBasicTypeName
|
||||
: this.timeStampVersionType;
|
||||
basicValue.setExplicitTypeName( explicitBasicTypeName );
|
||||
basicValue.setExplicitTypeParams( explicitLocalTypeParams );
|
||||
|
||||
|
@ -1188,10 +1190,9 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
if ( ( explicitCustomType != null && DynamicParameterizedType.class.isAssignableFrom( explicitCustomType ) )
|
||||
|| ( typeClass != null && DynamicParameterizedType.class.isAssignableFrom( typeClass ) ) ) {
|
||||
final Map<String, Object> parameters = createDynamicParameterizedTypeParameters();
|
||||
basicValue.setTypeParameters( (Map) parameters );
|
||||
if ( explicitCustomType != null && DynamicParameterizedType.class.isAssignableFrom( explicitCustomType )
|
||||
|| typeClass != null && DynamicParameterizedType.class.isAssignableFrom( typeClass ) ) {
|
||||
basicValue.setTypeParameters( createDynamicParameterizedTypeParameters() );
|
||||
}
|
||||
|
||||
if ( converterDescriptor != null ) {
|
||||
|
|
|
@ -101,6 +101,7 @@ import org.hibernate.cfg.AccessType;
|
|||
import org.hibernate.cfg.AnnotatedClassType;
|
||||
import org.hibernate.cfg.AnnotatedColumn;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumn;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumns;
|
||||
import org.hibernate.cfg.AnnotationBinder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.CollectionPropertyHolder;
|
||||
|
@ -135,6 +136,7 @@ import org.hibernate.mapping.Property;
|
|||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
@ -152,8 +154,8 @@ import static org.hibernate.cfg.AnnotatedColumn.buildColumnFromNoAnnotation;
|
|||
import static org.hibernate.cfg.AnnotatedColumn.buildColumnsFromAnnotations;
|
||||
import static org.hibernate.cfg.AnnotatedColumn.buildFormulaFromAnnotation;
|
||||
import static org.hibernate.cfg.AnnotatedColumn.checkPropertyConsistency;
|
||||
import static org.hibernate.cfg.AnnotatedJoinColumn.buildJoinColumnsWithDefaultColumnSuffix;
|
||||
import static org.hibernate.cfg.AnnotatedJoinColumn.buildJoinTableJoinColumns;
|
||||
import static org.hibernate.cfg.AnnotatedJoinColumns.buildJoinColumnsWithDefaultColumnSuffix;
|
||||
import static org.hibernate.cfg.AnnotatedJoinColumns.buildJoinTableJoinColumns;
|
||||
import static org.hibernate.cfg.AnnotationBinder.fillComponent;
|
||||
import static org.hibernate.cfg.BinderHelper.PRIMITIVE_NAMES;
|
||||
import static org.hibernate.cfg.BinderHelper.buildAnyValue;
|
||||
|
@ -201,7 +203,6 @@ public abstract class CollectionBinder {
|
|||
private String mappedBy;
|
||||
private XClass collectionElementType;
|
||||
private XClass targetEntity;
|
||||
protected AnnotatedJoinColumn[] inverseJoinColumns;
|
||||
private String cascadeStrategy;
|
||||
private String cacheConcurrencyStrategy;
|
||||
private String cacheRegionName;
|
||||
|
@ -211,8 +212,9 @@ public abstract class CollectionBinder {
|
|||
protected String mapKeyPropertyName;
|
||||
private boolean insertable = true;
|
||||
private boolean updatable = true;
|
||||
protected AnnotatedJoinColumn[] foreignJoinColumns;
|
||||
private AnnotatedJoinColumn[] joinColumns;
|
||||
protected AnnotatedJoinColumns inverseJoinColumns;
|
||||
protected AnnotatedJoinColumns foreignJoinColumns;
|
||||
private AnnotatedJoinColumns joinColumns;
|
||||
private boolean isExplicitAssociationTable;
|
||||
private AnnotatedColumn[] elementColumns;
|
||||
protected boolean isEmbedded;
|
||||
|
@ -220,7 +222,7 @@ public abstract class CollectionBinder {
|
|||
protected NotFoundAction notFoundAction;
|
||||
private TableBinder tableBinder;
|
||||
protected AnnotatedColumn[] mapKeyColumns;
|
||||
protected AnnotatedJoinColumn[] mapKeyManyToManyColumns;
|
||||
protected AnnotatedJoinColumns mapKeyManyToManyColumns;
|
||||
protected Map<String, IdentifierGeneratorDefinition> localGenerators;
|
||||
protected Map<XClass, InheritanceState> inheritanceStatePerClass;
|
||||
private XClass declaringClass;
|
||||
|
@ -258,7 +260,7 @@ public abstract class CollectionBinder {
|
|||
MetadataBuildingContext context,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
XProperty property,
|
||||
AnnotatedJoinColumn[] joinColumns) {
|
||||
AnnotatedJoinColumns joinColumns) {
|
||||
|
||||
final OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class );
|
||||
final ManyToMany manyToManyAnn = property.getAnnotation( ManyToMany.class );
|
||||
|
@ -302,8 +304,8 @@ public abstract class CollectionBinder {
|
|||
|
||||
collectionBinder.setCache( property.getAnnotation( Cache.class ) );
|
||||
collectionBinder.setPropertyHolder(propertyHolder);
|
||||
Cascade hibernateCascade = property.getAnnotation( Cascade.class );
|
||||
NotFound notFound = property.getAnnotation( NotFound.class );
|
||||
final Cascade hibernateCascade = property.getAnnotation( Cascade.class );
|
||||
final NotFound notFound = property.getAnnotation( NotFound.class );
|
||||
if ( notFound != null ) {
|
||||
if ( manyToManyAnn == null ) {
|
||||
throw new AnnotationException( "Collection '" + getPath( propertyHolder, inferredData )
|
||||
|
@ -337,7 +339,7 @@ public abstract class CollectionBinder {
|
|||
collectionBinder,
|
||||
comment
|
||||
);
|
||||
final AnnotatedJoinColumn[] mapJoinColumns = buildJoinColumnsWithDefaultColumnSuffix(
|
||||
final AnnotatedJoinColumns mapJoinColumns = buildJoinColumnsWithDefaultColumnSuffix(
|
||||
joinKeyColumns,
|
||||
comment,
|
||||
null,
|
||||
|
@ -377,8 +379,8 @@ public abstract class CollectionBinder {
|
|||
mappedBy
|
||||
);
|
||||
|
||||
OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
|
||||
boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action();
|
||||
final OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
|
||||
final boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action();
|
||||
collectionBinder.setCascadeDeleteEnabled( onDeleteCascade );
|
||||
if ( isIdentifierMapper ) {
|
||||
collectionBinder.setInsertable( false );
|
||||
|
@ -400,7 +402,7 @@ public abstract class CollectionBinder {
|
|||
PropertyData inferredData,
|
||||
MetadataBuildingContext context,
|
||||
XProperty property,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
OneToMany oneToManyAnn,
|
||||
ManyToMany manyToManyAnn,
|
||||
ElementCollection elementCollectionAnn,
|
||||
|
@ -412,15 +414,15 @@ public abstract class CollectionBinder {
|
|||
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData )
|
||||
+ "' is annotated both '@OneToMany' and '@ManyToMany'" );
|
||||
}
|
||||
String mappedBy = null;
|
||||
ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager();
|
||||
final String mappedBy;
|
||||
final ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager();
|
||||
if ( oneToManyAnn != null ) {
|
||||
for ( AnnotatedJoinColumn column : joinColumns) {
|
||||
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) {
|
||||
if ( column.isSecondary() ) {
|
||||
throw new NotYetImplementedException( "Collections having FK in secondary table" );
|
||||
}
|
||||
}
|
||||
collectionBinder.setFkJoinColumns(joinColumns);
|
||||
collectionBinder.setFkJoinColumns( joinColumns );
|
||||
mappedBy = oneToManyAnn.mappedBy();
|
||||
//noinspection unchecked
|
||||
collectionBinder.setTargetEntity( reflectionManager.toXClass( oneToManyAnn.targetEntity() ) );
|
||||
|
@ -430,7 +432,7 @@ public abstract class CollectionBinder {
|
|||
collectionBinder.setOneToMany( true );
|
||||
}
|
||||
else if ( elementCollectionAnn != null ) {
|
||||
for ( AnnotatedJoinColumn column : joinColumns ) {
|
||||
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) {
|
||||
if ( column.isSecondary() ) {
|
||||
throw new NotYetImplementedException( "Collections having FK in secondary table" );
|
||||
}
|
||||
|
@ -459,6 +461,9 @@ public abstract class CollectionBinder {
|
|||
);
|
||||
collectionBinder.setOneToMany( false );
|
||||
}
|
||||
else {
|
||||
mappedBy = null;
|
||||
}
|
||||
collectionBinder.setMappedBy( mappedBy );
|
||||
return mappedBy;
|
||||
}
|
||||
|
@ -588,11 +593,11 @@ public abstract class CollectionBinder {
|
|||
PropertyHolder propertyHolder,
|
||||
PropertyData inferredData,
|
||||
String mappedBy) {
|
||||
TableBinder associationTableBinder = new TableBinder();
|
||||
JoinColumn[] annJoins;
|
||||
JoinColumn[] annInverseJoins;
|
||||
JoinTable assocTable = propertyHolder.getJoinTable( property );
|
||||
CollectionTable collectionTable = property.getAnnotation( CollectionTable.class );
|
||||
final TableBinder associationTableBinder = new TableBinder();
|
||||
final JoinTable assocTable = propertyHolder.getJoinTable( property );
|
||||
final CollectionTable collectionTable = property.getAnnotation( CollectionTable.class );
|
||||
final JoinColumn[] annJoins;
|
||||
final JoinColumn[] annInverseJoins;
|
||||
if ( assocTable != null || collectionTable != null ) {
|
||||
|
||||
final String catalog;
|
||||
|
@ -603,7 +608,6 @@ public abstract class CollectionBinder {
|
|||
final JoinColumn[] inverseJoins;
|
||||
final Index[] jpaIndexes;
|
||||
|
||||
|
||||
//JPA 2 has priority
|
||||
if ( collectionTable != null ) {
|
||||
catalog = collectionTable.catalog();
|
||||
|
@ -647,7 +651,7 @@ public abstract class CollectionBinder {
|
|||
annJoins = null;
|
||||
annInverseJoins = null;
|
||||
}
|
||||
final AnnotatedJoinColumn[] joinColumns = buildJoinTableJoinColumns(
|
||||
final AnnotatedJoinColumns joinColumns = buildJoinTableJoinColumns(
|
||||
annJoins,
|
||||
entityBinder.getSecondaryTables(),
|
||||
propertyHolder,
|
||||
|
@ -655,7 +659,7 @@ public abstract class CollectionBinder {
|
|||
mappedBy,
|
||||
buildingContext
|
||||
);
|
||||
final AnnotatedJoinColumn[] inverseJoinColumns = buildJoinTableJoinColumns(
|
||||
final AnnotatedJoinColumns inverseJoinColumns = buildJoinTableJoinColumns(
|
||||
annInverseJoins,
|
||||
entityBinder.getSecondaryTables(),
|
||||
propertyHolder,
|
||||
|
@ -709,11 +713,11 @@ public abstract class CollectionBinder {
|
|||
this.accessType = accessType;
|
||||
}
|
||||
|
||||
public void setInverseJoinColumns(AnnotatedJoinColumn[] inverseJoinColumns) {
|
||||
public void setInverseJoinColumns(AnnotatedJoinColumns inverseJoinColumns) {
|
||||
this.inverseJoinColumns = inverseJoinColumns;
|
||||
}
|
||||
|
||||
public void setJoinColumns(AnnotatedJoinColumn[] joinColumns) {
|
||||
public void setJoinColumns(AnnotatedJoinColumns joinColumns) {
|
||||
this.joinColumns = joinColumns;
|
||||
}
|
||||
|
||||
|
@ -1491,8 +1495,8 @@ public abstract class CollectionBinder {
|
|||
&& !reversePropertyInJoin
|
||||
&& oneToMany
|
||||
&& !isExplicitAssociationTable
|
||||
&& ( joinColumns[0].isImplicit() && hasMappedBy() //implicit @JoinColumn
|
||||
|| !foreignJoinColumns[0].isImplicit() ) //this is an explicit @JoinColumn
|
||||
&& ( joinColumns.getColumns()[0].isImplicit() && hasMappedBy() //implicit @JoinColumn
|
||||
|| !foreignJoinColumns.getColumns()[0].isImplicit() ) //this is an explicit @JoinColumn
|
||||
) {
|
||||
//this is a foreign key
|
||||
bindOneToManySecondPass( persistentClasses );
|
||||
|
@ -1517,7 +1521,7 @@ public abstract class CollectionBinder {
|
|||
throw new AssertionFailure( "null was passed for argument property" );
|
||||
}
|
||||
|
||||
logOneToManySeconPass();
|
||||
logOneToManySecondPass();
|
||||
|
||||
final org.hibernate.mapping.OneToMany oneToMany =
|
||||
new org.hibernate.mapping.OneToMany( buildingContext, getCollection().getOwner() );
|
||||
|
@ -1525,27 +1529,28 @@ public abstract class CollectionBinder {
|
|||
oneToMany.setReferencedEntityName( getElementType().getName() );
|
||||
oneToMany.setNotFoundAction( notFoundAction );
|
||||
|
||||
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
|
||||
|
||||
final String assocClass = oneToMany.getReferencedEntityName();
|
||||
final PersistentClass associatedClass = persistentClasses.get( assocClass );
|
||||
final String referencedEntityName = oneToMany.getReferencedEntityName();
|
||||
final PersistentClass associatedClass = persistentClasses.get( referencedEntityName );
|
||||
handleJpaOrderBy( collection, associatedClass );
|
||||
final Map<String, Join> joins = collector.getJoins( assocClass );
|
||||
if ( associatedClass == null ) {
|
||||
throw new MappingException(
|
||||
String.format( "Association [%s] for entity [%s] references unmapped class [%s]",
|
||||
propertyName, propertyHolder.getClassName(), assocClass )
|
||||
propertyName, propertyHolder.getClassName(), referencedEntityName )
|
||||
);
|
||||
}
|
||||
oneToMany.setAssociatedClass( associatedClass );
|
||||
for ( AnnotatedJoinColumn column : foreignJoinColumns ) {
|
||||
column.setPersistentClass( associatedClass, joins, inheritanceStatePerClass );
|
||||
|
||||
final Map<String, Join> joins = buildingContext.getMetadataCollector().getJoins( referencedEntityName );
|
||||
foreignJoinColumns.setPersistentClass( associatedClass, joins, inheritanceStatePerClass );
|
||||
for ( AnnotatedJoinColumn column : foreignJoinColumns.getColumns() ) {
|
||||
column.setJoins( joins );
|
||||
//TODO: this is lame, should get the table from foreignJoinColumns
|
||||
collection.setCollectionTable( column.getTable() );
|
||||
}
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Mapping collection: %s -> %s", collection.getRole(), collection.getCollectionTable().getName() );
|
||||
}
|
||||
|
||||
bindFilters( false );
|
||||
handleWhere( false );
|
||||
|
||||
|
@ -1553,21 +1558,28 @@ public abstract class CollectionBinder {
|
|||
bindCollectionSecondPass( targetEntity, foreignJoinColumns, cascadeDeleteEnabled, buildingContext );
|
||||
|
||||
if ( !collection.isInverse() && !collection.getKey().isNullable() ) {
|
||||
// for non-inverse one-to-many, with a not-null fk, add a backref!
|
||||
final String entityName = oneToMany.getReferencedEntityName();
|
||||
final PersistentClass referenced = collector.getEntityBinding( entityName );
|
||||
final Backref backref = new Backref();
|
||||
final AnnotatedJoinColumn column = foreignJoinColumns[0];
|
||||
backref.setName( '_' + column.getPropertyName() + '_' + column.getLogicalColumnName() + "Backref" );
|
||||
backref.setUpdateable( false );
|
||||
backref.setSelectable( false );
|
||||
backref.setCollectionRole( collection.getRole() );
|
||||
backref.setEntityName( collection.getOwner().getEntityName() );
|
||||
backref.setValue( collection.getKey() );
|
||||
referenced.addProperty( backref );
|
||||
createOneToManyBackref( oneToMany );
|
||||
}
|
||||
}
|
||||
|
||||
private void createOneToManyBackref(org.hibernate.mapping.OneToMany oneToMany) {
|
||||
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
|
||||
// for non-inverse one-to-many, with a not-null fk, add a backref!
|
||||
final String entityName = oneToMany.getReferencedEntityName();
|
||||
final PersistentClass referenced = collector.getEntityBinding( entityName );
|
||||
final Backref backref = new Backref();
|
||||
final String backrefName = '_' + foreignJoinColumns.getPropertyName()
|
||||
+ '_' + foreignJoinColumns.getColumns()[0].getLogicalColumnName()
|
||||
+ "Backref";
|
||||
backref.setName( backrefName );
|
||||
backref.setUpdateable( false);
|
||||
backref.setSelectable( false );
|
||||
backref.setCollectionRole( collection.getRole() );
|
||||
backref.setEntityName( collection.getOwner().getEntityName() );
|
||||
backref.setValue( collection.getKey() );
|
||||
referenced.addProperty( backref );
|
||||
}
|
||||
|
||||
private void handleJpaOrderBy(Collection collection, PersistentClass associatedClass) {
|
||||
if ( jpaOrderBy != null ) {
|
||||
final String orderByFragment = buildOrderByClauseFromHql( jpaOrderBy.value(), associatedClass );
|
||||
|
@ -1578,24 +1590,24 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
|
||||
private void bindFilters(boolean hasAssociationTable) {
|
||||
Filter simpleFilter = property.getAnnotation( Filter.class );
|
||||
final Filter simpleFilter = property.getAnnotation( Filter.class );
|
||||
//set filtering
|
||||
//test incompatible choices
|
||||
//if ( StringHelper.isNotEmpty( where ) ) collection.setWhere( where );
|
||||
if ( simpleFilter != null ) {
|
||||
addFilter( hasAssociationTable, simpleFilter );
|
||||
}
|
||||
Filters filters = getOverridableAnnotation( property, Filters.class, buildingContext );
|
||||
final Filters filters = getOverridableAnnotation( property, Filters.class, buildingContext );
|
||||
if ( filters != null ) {
|
||||
for ( Filter filter : filters.value() ) {
|
||||
addFilter( hasAssociationTable, filter );
|
||||
}
|
||||
}
|
||||
FilterJoinTable simpleFilterJoinTable = property.getAnnotation( FilterJoinTable.class );
|
||||
final FilterJoinTable simpleFilterJoinTable = property.getAnnotation( FilterJoinTable.class );
|
||||
if ( simpleFilterJoinTable != null ) {
|
||||
addFilter( hasAssociationTable, simpleFilterJoinTable );
|
||||
}
|
||||
FilterJoinTables filterJoinTables = property.getAnnotation( FilterJoinTables.class );
|
||||
final FilterJoinTables filterJoinTables = property.getAnnotation( FilterJoinTables.class );
|
||||
if ( filterJoinTables != null ) {
|
||||
for ( FilterJoinTable filter : filterJoinTables.value() ) {
|
||||
addFilter( hasAssociationTable, filter );
|
||||
|
@ -1821,8 +1833,8 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
|
||||
private DependantValue buildCollectionKey(
|
||||
Collection collValue,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
Collection collection,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
boolean cascadeDeleteEnabled,
|
||||
boolean noConstraintByDefault,
|
||||
XProperty property,
|
||||
|
@ -1831,21 +1843,23 @@ public abstract class CollectionBinder {
|
|||
|
||||
// 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!
|
||||
overrideReferencedPropertyName( collValue, joinColumns, buildingContext );
|
||||
overrideReferencedPropertyName( collection, joinColumns, buildingContext );
|
||||
|
||||
String propRef = collValue.getReferencedPropertyName();
|
||||
final String referencedPropertyName = collection.getReferencedPropertyName();
|
||||
//binding key reference using column
|
||||
KeyValue keyVal = propRef == null
|
||||
? collValue.getOwner().getIdentifier()
|
||||
: (KeyValue) collValue.getOwner().getReferencedProperty(propRef).getValue();
|
||||
final PersistentClass owner = collection.getOwner();
|
||||
final KeyValue keyValue = referencedPropertyName == null
|
||||
? owner.getIdentifier()
|
||||
: (KeyValue) owner.getReferencedProperty( referencedPropertyName ).getValue();
|
||||
|
||||
DependantValue key = new DependantValue( buildingContext, collValue.getCollectionTable(), keyVal );
|
||||
final DependantValue key = new DependantValue( buildingContext, collection.getCollectionTable(), keyValue );
|
||||
key.setTypeName( null );
|
||||
checkPropertyConsistency( joinColumns, collValue.getOwnerEntityName() );
|
||||
key.setNullable( joinColumns.length == 0 || joinColumns[0].isNullable() );
|
||||
key.setUpdateable( joinColumns.length == 0 || joinColumns[0].isUpdatable() );
|
||||
final AnnotatedJoinColumn[] columns = joinColumns.getColumns();
|
||||
checkPropertyConsistency( columns, collection.getOwnerEntityName() );
|
||||
key.setNullable( columns.length == 0 || columns[0].isNullable() );
|
||||
key.setUpdateable( columns.length == 0 || columns[0].isUpdatable() );
|
||||
key.setCascadeDeleteEnabled( cascadeDeleteEnabled );
|
||||
collValue.setKey( key );
|
||||
collection.setKey( key );
|
||||
|
||||
if ( property != null ) {
|
||||
final org.hibernate.annotations.ForeignKey fk = property.getAnnotation( org.hibernate.annotations.ForeignKey.class );
|
||||
|
@ -1855,17 +1869,18 @@ public abstract class CollectionBinder {
|
|||
else {
|
||||
final CollectionTable collectionTableAnn = property.getAnnotation( CollectionTable.class );
|
||||
if ( collectionTableAnn != null ) {
|
||||
if ( collectionTableAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT
|
||||
|| collectionTableAnn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) {
|
||||
final ForeignKey foreignKey = collectionTableAnn.foreignKey();
|
||||
if ( foreignKey.value() == ConstraintMode.NO_CONSTRAINT
|
||||
|| foreignKey.value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) {
|
||||
key.disableForeignKey();
|
||||
}
|
||||
else {
|
||||
key.setForeignKeyName( nullIfEmpty( collectionTableAnn.foreignKey().name() ) );
|
||||
key.setForeignKeyDefinition( nullIfEmpty( collectionTableAnn.foreignKey().foreignKeyDefinition() ) );
|
||||
if ( key.getForeignKeyName() == null &&
|
||||
key.getForeignKeyDefinition() == null &&
|
||||
collectionTableAnn.joinColumns().length == 1 ) {
|
||||
JoinColumn joinColumn = collectionTableAnn.joinColumns()[0];
|
||||
key.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
|
||||
key.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
|
||||
if ( key.getForeignKeyName() == null
|
||||
&& key.getForeignKeyDefinition() == null
|
||||
&& collectionTableAnn.joinColumns().length == 1 ) {
|
||||
final JoinColumn joinColumn = collectionTableAnn.joinColumns()[0];
|
||||
key.setForeignKeyName( nullIfEmpty( joinColumn.foreignKey().name() ) );
|
||||
key.setForeignKeyDefinition( nullIfEmpty( joinColumn.foreignKey().foreignKeyDefinition() ) );
|
||||
}
|
||||
|
@ -1874,9 +1889,10 @@ public abstract class CollectionBinder {
|
|||
else {
|
||||
final JoinTable joinTableAnn = property.getAnnotation( JoinTable.class );
|
||||
if ( joinTableAnn != null ) {
|
||||
String foreignKeyName = joinTableAnn.foreignKey().name();
|
||||
String foreignKeyDefinition = joinTableAnn.foreignKey().foreignKeyDefinition();
|
||||
ConstraintMode foreignKeyValue = joinTableAnn.foreignKey().value();
|
||||
final ForeignKey foreignKey = joinTableAnn.foreignKey();
|
||||
String foreignKeyName = foreignKey.name();
|
||||
String foreignKeyDefinition = foreignKey.foreignKeyDefinition();
|
||||
ConstraintMode foreignKeyValue = foreignKey.value();
|
||||
if ( joinTableAnn.joinColumns().length != 0 ) {
|
||||
final JoinColumn joinColumnAnn = joinTableAnn.joinColumns()[0];
|
||||
if ( foreignKeyName != null && foreignKeyName.isEmpty() ) {
|
||||
|
@ -1897,22 +1913,16 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
else {
|
||||
final String propertyPath = qualify(propertyHolder.getPath(), property.getName());
|
||||
final String propertyPath = qualify( propertyHolder.getPath(), property.getName() );
|
||||
final ForeignKey foreignKey = propertyHolder.getOverriddenForeignKey( propertyPath );
|
||||
if ( foreignKey != null ) {
|
||||
if ( foreignKey.value() == ConstraintMode.NO_CONSTRAINT
|
||||
|| foreignKey.value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) {
|
||||
key.disableForeignKey();
|
||||
}
|
||||
else {
|
||||
key.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
|
||||
key.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
|
||||
}
|
||||
handleForeignKeyConstraint( noConstraintByDefault, key, foreignKey );
|
||||
}
|
||||
else {
|
||||
final OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class );
|
||||
final OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
|
||||
if ( oneToManyAnn != null && !oneToManyAnn.mappedBy().isEmpty()
|
||||
if ( oneToManyAnn != null
|
||||
&& !oneToManyAnn.mappedBy().isEmpty()
|
||||
&& ( onDeleteAnn == null || onDeleteAnn.action() != OnDeleteAction.CASCADE ) ) {
|
||||
// foreign key should be up to @ManyToOne side
|
||||
// @OnDelete generate "on delete cascade" foreign key
|
||||
|
@ -1921,14 +1931,7 @@ public abstract class CollectionBinder {
|
|||
else {
|
||||
final JoinColumn joinColumnAnn = property.getAnnotation( JoinColumn.class );
|
||||
if ( joinColumnAnn != null ) {
|
||||
if ( joinColumnAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT
|
||||
|| joinColumnAnn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) {
|
||||
key.disableForeignKey();
|
||||
}
|
||||
else {
|
||||
key.setForeignKeyName( nullIfEmpty( joinColumnAnn.foreignKey().name() ) );
|
||||
key.setForeignKeyDefinition( nullIfEmpty( joinColumnAnn.foreignKey().foreignKeyDefinition() ) );
|
||||
}
|
||||
handleForeignKeyConstraint( noConstraintByDefault, key, joinColumnAnn.foreignKey() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1940,22 +1943,31 @@ public abstract class CollectionBinder {
|
|||
return key;
|
||||
}
|
||||
|
||||
private static void handleForeignKeyConstraint(boolean noConstraintByDefault, DependantValue key, ForeignKey foreignKey) {
|
||||
final ConstraintMode constraintMode = foreignKey.value();
|
||||
if ( constraintMode == ConstraintMode.NO_CONSTRAINT
|
||||
|| constraintMode == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault) {
|
||||
key.disableForeignKey();
|
||||
}
|
||||
else {
|
||||
key.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
|
||||
key.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void overrideReferencedPropertyName(
|
||||
Collection collection,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
MetadataBuildingContext context) {
|
||||
if ( joinColumns.length > 0 ) {
|
||||
AnnotatedJoinColumn joinColumn = joinColumns[0];
|
||||
if ( hasMappedBy() ) {
|
||||
final String entityName = joinColumn.getManyToManyOwnerSideEntityName() != null
|
||||
? "inverse__" + joinColumn.getManyToManyOwnerSideEntityName()
|
||||
: joinColumn.getPropertyHolder().getEntityName();
|
||||
final InFlightMetadataCollector collector = context.getMetadataCollector();
|
||||
final String referencedProperty = collector.getPropertyReferencedAssociation( entityName, mappedBy );
|
||||
if ( referencedProperty != null ) {
|
||||
collection.setReferencedPropertyName( referencedProperty );
|
||||
collector.addPropertyReference( collection.getOwnerEntityName(), referencedProperty );
|
||||
}
|
||||
if ( hasMappedBy() && joinColumns.getColumns().length > 0 ) {
|
||||
final String entityName = joinColumns.getManyToManyOwnerSideEntityName() != null
|
||||
? "inverse__" + joinColumns.getManyToManyOwnerSideEntityName()
|
||||
: joinColumns.getPropertyHolder().getEntityName();
|
||||
final InFlightMetadataCollector collector = context.getMetadataCollector();
|
||||
final String referencedProperty = collector.getPropertyReferencedAssociation( entityName, mappedBy );
|
||||
if ( referencedProperty != null ) {
|
||||
collection.setReferencedPropertyName( referencedProperty );
|
||||
collector.addPropertyReference( collection.getOwnerEntityName(), referencedProperty );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2195,15 +2207,15 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
|
||||
private ManyToOne handleCollectionOfEntities(
|
||||
Collection collValue,
|
||||
Collection collection,
|
||||
XClass elementType,
|
||||
NotFoundAction notFoundAction,
|
||||
XProperty property,
|
||||
MetadataBuildingContext buildingContext,
|
||||
PersistentClass collectionEntity,
|
||||
String hqlOrderBy) {
|
||||
ManyToOne element = new ManyToOne( buildingContext, collValue.getCollectionTable() );
|
||||
collValue.setElement( element );
|
||||
ManyToOne element = new ManyToOne( buildingContext, collection.getCollectionTable() );
|
||||
collection.setElement( element );
|
||||
element.setReferencedEntityName( elementType.getName() );
|
||||
//element.setFetchMode( fetchMode );
|
||||
//element.setLazy( fetchMode != FetchMode.JOIN );
|
||||
|
@ -2213,7 +2225,7 @@ public abstract class CollectionBinder {
|
|||
element.setNotFoundAction( notFoundAction );
|
||||
// as per 11.1.38 of JPA 2.0 spec, default to primary key if no column is specified by @OrderBy.
|
||||
if ( hqlOrderBy != null ) {
|
||||
collValue.setManyToManyOrdering( buildOrderByClauseFromHql( hqlOrderBy, collectionEntity ) );
|
||||
collection.setManyToManyOrdering( buildOrderByClauseFromHql( hqlOrderBy, collectionEntity ) );
|
||||
}
|
||||
|
||||
final org.hibernate.annotations.ForeignKey fk = property.getAnnotation( org.hibernate.annotations.ForeignKey.class );
|
||||
|
@ -2247,8 +2259,8 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
|
||||
private void handleManyToAny(
|
||||
Collection collValue,
|
||||
AnnotatedJoinColumn[] inverseJoinColumns,
|
||||
Collection collection,
|
||||
AnnotatedJoinColumns inverseJoinColumns,
|
||||
boolean cascadeDeleteEnabled,
|
||||
XProperty property,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
|
@ -2266,8 +2278,8 @@ public abstract class CollectionBinder {
|
|||
final Formula discriminatorFormulaAnn = getOverridableAnnotation( prop, Formula.class, buildingContext);
|
||||
|
||||
//override the table
|
||||
for (AnnotatedColumn column : inverseJoinColumns) {
|
||||
column.setTable( collValue.getCollectionTable() );
|
||||
for ( AnnotatedColumn column : inverseJoinColumns.getColumns() ) {
|
||||
column.setTable( collection.getCollectionTable() );
|
||||
}
|
||||
|
||||
ManyToAny anyAnn = property.getAnnotation( ManyToAny.class );
|
||||
|
@ -2284,33 +2296,33 @@ public abstract class CollectionBinder {
|
|||
true,
|
||||
buildingContext
|
||||
);
|
||||
collValue.setElement( any );
|
||||
collection.setElement( any );
|
||||
}
|
||||
|
||||
private PropertyData getSpecialMembers(XClass elementClass) {
|
||||
if ( isMap() ) {
|
||||
//"value" is the JPA 2 prefix for map values (used to be "element")
|
||||
if ( isHibernateExtensionMapping() ) {
|
||||
return new PropertyPreloadedData( AccessType.PROPERTY, "element", elementClass);
|
||||
return new PropertyPreloadedData( AccessType.PROPERTY, "element", elementClass );
|
||||
}
|
||||
else {
|
||||
return new PropertyPreloadedData( AccessType.PROPERTY, "value", elementClass);
|
||||
return new PropertyPreloadedData( AccessType.PROPERTY, "value", elementClass );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( isHibernateExtensionMapping() ) {
|
||||
return new PropertyPreloadedData( AccessType.PROPERTY, "element", elementClass);
|
||||
return new PropertyPreloadedData( AccessType.PROPERTY, "element", elementClass );
|
||||
}
|
||||
else {
|
||||
//"collection&&element" is not a valid property name => placeholder
|
||||
return new PropertyPreloadedData( AccessType.PROPERTY, "collection&&element", elementClass);
|
||||
return new PropertyPreloadedData( AccessType.PROPERTY, "collection&&element", elementClass );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOwnedManyToMany(
|
||||
Collection collection,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
TableBinder associationTableBinder,
|
||||
XProperty property,
|
||||
MetadataBuildingContext context,
|
||||
|
@ -2320,15 +2332,11 @@ public abstract class CollectionBinder {
|
|||
//FIXME NamingStrategy
|
||||
final InFlightMetadataCollector collector = context.getMetadataCollector();
|
||||
final PersistentClass owner = collection.getOwner();
|
||||
for ( AnnotatedJoinColumn column : joinColumns ) {
|
||||
column.setMappedBy(
|
||||
owner.getEntityName(),
|
||||
collector.getLogicalTableName( owner.getTable() ),
|
||||
collector.getFromMappedBy( owner.getEntityName(), column.getPropertyName() )
|
||||
);
|
||||
// String header = ( mappedByProperty == null ) ? mappings.getLogicalTableName( ownerTable ) : mappedByProperty;
|
||||
// column.setDefaultColumnHeader( header );
|
||||
}
|
||||
joinColumns.setMappedBy(
|
||||
owner.getEntityName(),
|
||||
collector.getLogicalTableName( owner.getTable() ),
|
||||
collector.getFromMappedBy( owner.getEntityName(), joinColumns.getPropertyName() )
|
||||
);
|
||||
if ( isEmpty( associationTableBinder.getName() ) ) {
|
||||
//default value
|
||||
associationTableBinder.setDefaultName(
|
||||
|
@ -2340,7 +2348,7 @@ public abstract class CollectionBinder {
|
|||
collectionEntity != null ? collectionEntity.getEntityName() : null,
|
||||
collectionEntity != null ? collectionEntity.getJpaEntityName() : null,
|
||||
collectionEntity != null ? collector.getLogicalTableName( collectionEntity.getTable() ) : null,
|
||||
joinColumns[0].getPropertyName()
|
||||
joinColumns.getPropertyName()
|
||||
);
|
||||
}
|
||||
associationTableBinder.setJPA2ElementCollection(
|
||||
|
@ -2350,8 +2358,8 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
|
||||
private void handleUnownedManyToMany(
|
||||
Collection collValue,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
Collection collection,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
XClass elementType,
|
||||
PersistentClass collectionEntity,
|
||||
boolean isCollectionOfEntities) {
|
||||
|
@ -2361,7 +2369,9 @@ public abstract class CollectionBinder {
|
|||
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
|
||||
}
|
||||
|
||||
Property otherSideProperty;
|
||||
joinColumns.setManyToManyOwnerSideEntityName( collectionEntity.getEntityName() );
|
||||
|
||||
final Property otherSideProperty;
|
||||
try {
|
||||
otherSideProperty = collectionEntity.getRecursiveProperty( mappedBy );
|
||||
}
|
||||
|
@ -2370,17 +2380,13 @@ public abstract class CollectionBinder {
|
|||
"is 'mappedBy' a property named '" + mappedBy
|
||||
+ "' which does not exist in the target entity '" + elementType.getName() + "'" );
|
||||
}
|
||||
Table table = otherSideProperty.getValue() instanceof Collection
|
||||
? ( (Collection) otherSideProperty.getValue() ).getCollectionTable()
|
||||
: otherSideProperty.getValue().getTable();
|
||||
//this is a collection on the other side
|
||||
//This is a ToOne with a @JoinTable or a regular property
|
||||
collValue.setCollectionTable( table );
|
||||
String entityName = collectionEntity.getEntityName();
|
||||
for (AnnotatedJoinColumn column : joinColumns) {
|
||||
//column.setDefaultColumnHeader( joinColumns[0].getMappedBy() ); //seems not to be used, make sense
|
||||
column.setManyToManyOwnerSideEntityName( entityName );
|
||||
}
|
||||
final Value otherSidePropertyValue = otherSideProperty.getValue();
|
||||
final Table table = otherSidePropertyValue instanceof Collection
|
||||
// this is a collection on the other side
|
||||
? ( (Collection) otherSidePropertyValue ).getCollectionTable()
|
||||
// this is a ToOne with a @JoinTable or a regular property
|
||||
: otherSidePropertyValue.getTable();
|
||||
collection.setCollectionTable( table );
|
||||
}
|
||||
|
||||
private void detectManyToManyProblems(
|
||||
|
@ -2402,7 +2408,7 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
else {
|
||||
JoinTable joinTableAnn = parentPropertyHolder.getJoinTable( property );
|
||||
final JoinTable joinTableAnn = parentPropertyHolder.getJoinTable( property );
|
||||
if ( joinTableAnn != null && joinTableAnn.inverseJoinColumns().length > 0 ) {
|
||||
throw new AnnotationException( "Association '" + safeCollectionRole()
|
||||
+ " has a '@JoinTable' with 'inverseJoinColumns' and targets the type '"
|
||||
|
@ -2479,7 +2485,7 @@ public abstract class CollectionBinder {
|
|||
|
||||
private void bindCollectionSecondPass(
|
||||
PersistentClass targetEntity,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
boolean cascadeDeleteEnabled,
|
||||
MetadataBuildingContext context) {
|
||||
|
||||
|
@ -2505,9 +2511,8 @@ public abstract class CollectionBinder {
|
|||
context
|
||||
);
|
||||
|
||||
//TODO: this is really warty
|
||||
if ( property.isAnnotationPresent( ElementCollection.class ) && joinColumns.length > 0 ) {
|
||||
joinColumns[0].setJPA2ElementCollection( true );
|
||||
if ( property.isAnnotationPresent( ElementCollection.class ) ) {
|
||||
joinColumns.setElementCollection( true );
|
||||
}
|
||||
|
||||
TableBinder.bindForeignKey(
|
||||
|
@ -2529,7 +2534,6 @@ public abstract class CollectionBinder {
|
|||
return propertyHolder != null ? propertyHolder.getEntityName() + "." + propertyName : "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bind the inverse foreign key of a {@link ManyToMany}, that is, the columns
|
||||
* specified by {@code @JoinTable(inverseJoinColumns=...)}, which are the
|
||||
|
@ -2539,15 +2543,16 @@ public abstract class CollectionBinder {
|
|||
*/
|
||||
public void bindManyToManyInverseForeignKey(
|
||||
PersistentClass targetEntity,
|
||||
AnnotatedJoinColumn[] columns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
SimpleValue value,
|
||||
boolean unique,
|
||||
MetadataBuildingContext context) {
|
||||
if ( hasMappedBy() ) {
|
||||
final Property property = targetEntity.getRecursiveProperty( mappedBy );
|
||||
final List<Selectable> mappedByColumns = mappedByColumns( targetEntity, property );
|
||||
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0];
|
||||
for ( Selectable selectable: mappedByColumns ) {
|
||||
columns[0].linkValueUsingAColumnCopy( (Column) selectable, value );
|
||||
firstColumn.linkValueUsingAColumnCopy( (Column) selectable, value );
|
||||
}
|
||||
final String referencedPropertyName = context.getMetadataCollector()
|
||||
.getPropertyReferencedAssociation( targetEntity.getEntityName(), mappedBy );
|
||||
|
@ -2562,7 +2567,7 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
else {
|
||||
createSyntheticPropertyReference(
|
||||
columns,
|
||||
joinColumns,
|
||||
targetEntity,
|
||||
collection.getOwner(),
|
||||
value,
|
||||
|
@ -2576,7 +2581,7 @@ public abstract class CollectionBinder {
|
|||
TableBinder.bindForeignKey(
|
||||
targetEntity,
|
||||
collection.getOwner(),
|
||||
columns,
|
||||
joinColumns,
|
||||
value,
|
||||
unique,
|
||||
context
|
||||
|
@ -2604,7 +2609,7 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
public void setFkJoinColumns(AnnotatedJoinColumn[] annotatedJoinColumns) {
|
||||
public void setFkJoinColumns(AnnotatedJoinColumns annotatedJoinColumns) {
|
||||
this.foreignJoinColumns = annotatedJoinColumns;
|
||||
}
|
||||
|
||||
|
@ -2636,7 +2641,7 @@ public abstract class CollectionBinder {
|
|||
this.mapKeyColumns = mapKeyColumns;
|
||||
}
|
||||
|
||||
public void setMapKeyManyToManyColumns(AnnotatedJoinColumn[] mapJoinColumns) {
|
||||
public void setMapKeyManyToManyColumns(AnnotatedJoinColumns mapJoinColumns) {
|
||||
this.mapKeyManyToManyColumns = mapJoinColumns;
|
||||
}
|
||||
|
||||
|
@ -2644,7 +2649,7 @@ public abstract class CollectionBinder {
|
|||
this.localGenerators = localGenerators;
|
||||
}
|
||||
|
||||
private void logOneToManySeconPass() {
|
||||
private void logOneToManySecondPass() {
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Binding a OneToMany: %s through a foreign key", safeCollectionRole() );
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ import org.hibernate.boot.spi.MetadataBuildingContext;
|
|||
import org.hibernate.cfg.AccessType;
|
||||
import org.hibernate.cfg.AnnotatedClassType;
|
||||
import org.hibernate.cfg.AnnotatedDiscriminatorColumn;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumns;
|
||||
import org.hibernate.cfg.AnnotationBinder;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumn;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
@ -217,7 +218,7 @@ public class EntityBinder {
|
|||
final PersistentClass persistentClass = makePersistentClass( inheritanceState, superEntity, context);
|
||||
final EntityBinder entityBinder = new EntityBinder( clazzToProcess, persistentClass, context );
|
||||
|
||||
final AnnotatedJoinColumn[] inheritanceJoinedColumns =
|
||||
final AnnotatedJoinColumns inheritanceJoinedColumns =
|
||||
makeInheritanceJoinColumns( clazzToProcess, context, inheritanceState, superEntity );
|
||||
final AnnotatedDiscriminatorColumn discriminatorColumn =
|
||||
handleDiscriminatorColumn( clazzToProcess, context, inheritanceState, entityBinder );
|
||||
|
@ -673,7 +674,7 @@ public class EntityBinder {
|
|||
InheritanceState inheritanceState,
|
||||
PersistentClass persistentClass,
|
||||
EntityBinder entityBinder,
|
||||
AnnotatedJoinColumn[] inheritanceJoinedColumns,
|
||||
AnnotatedJoinColumns inheritanceJoinedColumns,
|
||||
AnnotatedDiscriminatorColumn discriminatorColumn,
|
||||
PropertyHolder propertyHolder) {
|
||||
|
||||
|
@ -984,7 +985,7 @@ public class EntityBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private static AnnotatedJoinColumn[] makeInheritanceJoinColumns(
|
||||
private static AnnotatedJoinColumns makeInheritanceJoinColumns(
|
||||
XClass clazzToProcess,
|
||||
MetadataBuildingContext context,
|
||||
InheritanceState inheritanceState,
|
||||
|
@ -995,7 +996,7 @@ public class EntityBinder {
|
|||
&& InheritanceType.JOINED == inheritanceState.getType();
|
||||
if ( hasJoinedColumns ) {
|
||||
//@Inheritance(JOINED) subclass need to link back to the super entity
|
||||
PrimaryKeyJoinColumns jcsAnn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class );
|
||||
final PrimaryKeyJoinColumns jcsAnn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class );
|
||||
boolean explicitInheritanceJoinedColumns = jcsAnn != null && jcsAnn.value().length != 0;
|
||||
if ( explicitInheritanceJoinedColumns ) {
|
||||
int nbrOfInhJoinedColumns = jcsAnn.value().length;
|
||||
|
@ -1014,7 +1015,7 @@ public class EntityBinder {
|
|||
}
|
||||
}
|
||||
else {
|
||||
PrimaryKeyJoinColumn jcAnn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class );
|
||||
final PrimaryKeyJoinColumn jcAnn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class );
|
||||
inheritanceJoinedColumns = new AnnotatedJoinColumn[1];
|
||||
inheritanceJoinedColumns[0] = buildJoinColumn(
|
||||
jcAnn,
|
||||
|
@ -1033,7 +1034,15 @@ public class EntityBinder {
|
|||
LOG.invalidPrimaryKeyJoinColumnAnnotation( clazzToProcess.getName() );
|
||||
}
|
||||
}
|
||||
return inheritanceJoinedColumns;
|
||||
if ( inheritanceJoinedColumns == null ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
|
||||
joinColumns.setBuildingContext( context );
|
||||
joinColumns.setColumns( inheritanceJoinedColumns );
|
||||
return joinColumns;
|
||||
}
|
||||
}
|
||||
|
||||
private static PersistentClass getSuperEntity(
|
||||
|
@ -1746,24 +1755,23 @@ public class EntityBinder {
|
|||
}
|
||||
|
||||
private void createPrimaryColumnsToSecondaryTable(Object column, PropertyHolder propertyHolder, Join join) {
|
||||
final AnnotatedJoinColumn[] annotatedJoinColumns;
|
||||
final PrimaryKeyJoinColumn[] pkColumnsAnn = column instanceof PrimaryKeyJoinColumn[]
|
||||
? (PrimaryKeyJoinColumn[]) column
|
||||
: null;
|
||||
final JoinColumn[] joinColumnsAnn = column instanceof JoinColumn[]
|
||||
? (JoinColumn[]) column
|
||||
: null;
|
||||
annotatedJoinColumns = pkColumnsAnn == null && joinColumnsAnn == null
|
||||
final AnnotatedJoinColumns annotatedJoinColumns = pkColumnsAnn == null && joinColumnsAnn == null
|
||||
? createDefaultJoinColumn( propertyHolder )
|
||||
: createJoinColumns( propertyHolder, pkColumnsAnn, joinColumnsAnn );
|
||||
|
||||
for (AnnotatedJoinColumn joinColumn : annotatedJoinColumns) {
|
||||
for ( AnnotatedJoinColumn joinColumn : annotatedJoinColumns.getColumns() ) {
|
||||
joinColumn.forceNotNull();
|
||||
}
|
||||
bindJoinToPersistentClass( join, annotatedJoinColumns, context );
|
||||
}
|
||||
|
||||
private AnnotatedJoinColumn[] createDefaultJoinColumn(PropertyHolder propertyHolder) {
|
||||
private AnnotatedJoinColumns createDefaultJoinColumn(PropertyHolder propertyHolder) {
|
||||
final AnnotatedJoinColumn[] annotatedJoinColumns = new AnnotatedJoinColumn[1];
|
||||
annotatedJoinColumns[0] = buildJoinColumn(
|
||||
null,
|
||||
|
@ -1773,10 +1781,14 @@ public class EntityBinder {
|
|||
propertyHolder,
|
||||
context
|
||||
);
|
||||
return annotatedJoinColumns;
|
||||
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
|
||||
joinColumns.setBuildingContext( context );
|
||||
joinColumns.setPropertyHolder( propertyHolder );
|
||||
joinColumns.setColumns( annotatedJoinColumns );
|
||||
return joinColumns;
|
||||
}
|
||||
|
||||
private AnnotatedJoinColumn[] createJoinColumns(
|
||||
private AnnotatedJoinColumns createJoinColumns(
|
||||
PropertyHolder propertyHolder,
|
||||
PrimaryKeyJoinColumn[] pkColumnsAnn,
|
||||
JoinColumn[] joinColumnsAnn) {
|
||||
|
@ -1787,8 +1799,8 @@ public class EntityBinder {
|
|||
else {
|
||||
final AnnotatedJoinColumn[] annotatedJoinColumns = new AnnotatedJoinColumn[joinColumnCount];
|
||||
for (int colIndex = 0; colIndex < joinColumnCount; colIndex++) {
|
||||
PrimaryKeyJoinColumn pkJoinAnn = pkColumnsAnn != null ? pkColumnsAnn[colIndex] : null;
|
||||
JoinColumn joinAnn = joinColumnsAnn != null ? joinColumnsAnn[colIndex] : null;
|
||||
final PrimaryKeyJoinColumn pkJoinAnn = pkColumnsAnn != null ? pkColumnsAnn[colIndex] : null;
|
||||
final JoinColumn joinAnn = joinColumnsAnn != null ? joinColumnsAnn[colIndex] : null;
|
||||
annotatedJoinColumns[colIndex] = buildJoinColumn(
|
||||
pkJoinAnn,
|
||||
joinAnn,
|
||||
|
@ -1798,11 +1810,15 @@ public class EntityBinder {
|
|||
context
|
||||
);
|
||||
}
|
||||
return annotatedJoinColumns;
|
||||
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
|
||||
joinColumns.setBuildingContext( context );
|
||||
joinColumns.setPropertyHolder( propertyHolder );
|
||||
joinColumns.setColumns( annotatedJoinColumns );
|
||||
return joinColumns;
|
||||
}
|
||||
}
|
||||
|
||||
private void bindJoinToPersistentClass(Join join, AnnotatedJoinColumn[] joinColumns, MetadataBuildingContext context) {
|
||||
private void bindJoinToPersistentClass(Join join, AnnotatedJoinColumns joinColumns, MetadataBuildingContext context) {
|
||||
DependantValue key = new DependantValue( context, join.getTable(), persistentClass.getIdentifier() );
|
||||
join.setKey( key );
|
||||
setForeignKeyNameIfDefined( join );
|
||||
|
@ -1822,7 +1838,7 @@ public class EntityBinder {
|
|||
key.setForeignKeyName( matchingTable.foreignKey().name() );
|
||||
}
|
||||
else {
|
||||
SecondaryTable jpaSecondaryTable = findMatchingSecondaryTable( join );
|
||||
final SecondaryTable jpaSecondaryTable = findMatchingSecondaryTable( join );
|
||||
if ( jpaSecondaryTable != null ) {
|
||||
final boolean noConstraintByDefault = context.getBuildingOptions().isNoConstraintByDefault();
|
||||
if ( jpaSecondaryTable.foreignKey().value() == ConstraintMode.NO_CONSTRAINT
|
||||
|
@ -1839,11 +1855,11 @@ public class EntityBinder {
|
|||
|
||||
private SecondaryTable findMatchingSecondaryTable(Join join) {
|
||||
final String nameToMatch = join.getTable().getQuotedName();
|
||||
SecondaryTable secondaryTable = annotatedClass.getAnnotation( SecondaryTable.class );
|
||||
final SecondaryTable secondaryTable = annotatedClass.getAnnotation( SecondaryTable.class );
|
||||
if ( secondaryTable != null && nameToMatch.equals( secondaryTable.name() ) ) {
|
||||
return secondaryTable;
|
||||
}
|
||||
SecondaryTables secondaryTables = annotatedClass.getAnnotation( SecondaryTables.class );
|
||||
final SecondaryTables secondaryTables = annotatedClass.getAnnotation( SecondaryTables.class );
|
||||
if ( secondaryTables != null ) {
|
||||
for ( SecondaryTable secondaryTablesEntry : secondaryTables.value() ) {
|
||||
if ( secondaryTablesEntry != null && nameToMatch.equals( secondaryTablesEntry.name() ) ) {
|
||||
|
@ -1856,7 +1872,7 @@ public class EntityBinder {
|
|||
|
||||
private org.hibernate.annotations.Table findMatchingComplementaryTableAnnotation(Join join) {
|
||||
final String tableName = join.getTable().getQuotedName();
|
||||
org.hibernate.annotations.Table table = annotatedClass.getAnnotation( org.hibernate.annotations.Table.class );
|
||||
final org.hibernate.annotations.Table table = annotatedClass.getAnnotation( org.hibernate.annotations.Table.class );
|
||||
if ( table != null && tableName.equals( table.appliesTo() ) ) {
|
||||
return table;
|
||||
}
|
||||
|
@ -1875,7 +1891,7 @@ public class EntityBinder {
|
|||
|
||||
private SecondaryRow findMatchingComplementarySecondaryRowAnnotation(Join join) {
|
||||
final String tableName = join.getTable().getQuotedName();
|
||||
SecondaryRow row = annotatedClass.getAnnotation( SecondaryRow.class );
|
||||
final SecondaryRow row = annotatedClass.getAnnotation( SecondaryRow.class );
|
||||
if ( row != null && ( row.table().isEmpty() || tableName.equals( row.table() ) ) ) {
|
||||
return row;
|
||||
}
|
||||
|
@ -1907,7 +1923,7 @@ public class EntityBinder {
|
|||
PropertyHolder propertyHolder,
|
||||
boolean noDelayInPkColumnCreation) {
|
||||
// A non-null propertyHolder means than we process the Pk creation without delay
|
||||
Join join = new Join();
|
||||
final Join join = new Join();
|
||||
join.setPersistentClass( persistentClass );
|
||||
|
||||
final String schema;
|
||||
|
@ -1979,8 +1995,8 @@ public class EntityBinder {
|
|||
//Has to do the work later because it needs persistentClass id!
|
||||
LOG.debugf( "Adding secondary table to entity %s -> %s",
|
||||
persistentClass.getEntityName(), join.getTable().getName() );
|
||||
SecondaryRow matchingRow = findMatchingComplementarySecondaryRowAnnotation( join );
|
||||
org.hibernate.annotations.Table matchingTable = findMatchingComplementaryTableAnnotation( join );
|
||||
final SecondaryRow matchingRow = findMatchingComplementarySecondaryRowAnnotation( join );
|
||||
final org.hibernate.annotations.Table matchingTable = findMatchingComplementaryTableAnnotation( join );
|
||||
if ( matchingRow != null ) {
|
||||
join.setInverse( !matchingRow.owned() );
|
||||
join.setOptional( matchingRow.optional() );
|
||||
|
@ -2042,7 +2058,7 @@ public class EntityBinder {
|
|||
}
|
||||
|
||||
public static String getCacheConcurrencyStrategy(CacheConcurrencyStrategy strategy) {
|
||||
org.hibernate.cache.spi.access.AccessType accessType = strategy.toAccessType();
|
||||
final org.hibernate.cache.spi.access.AccessType accessType = strategy.toAccessType();
|
||||
return accessType == null ? null : accessType.getExternalName();
|
||||
}
|
||||
|
||||
|
@ -2100,9 +2116,10 @@ public class EntityBinder {
|
|||
}
|
||||
|
||||
public void processComplementaryTableDefinitions(Tables tables) {
|
||||
if ( tables == null ) return;
|
||||
for (org.hibernate.annotations.Table table : tables.value()) {
|
||||
processComplementaryTableDefinitions( table );
|
||||
if ( tables != null ) {
|
||||
for ( org.hibernate.annotations.Table table : tables.value() ) {
|
||||
processComplementaryTableDefinitions( table );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2128,7 +2145,7 @@ public class EntityBinder {
|
|||
|
||||
public AccessType getExplicitAccessType(XAnnotatedElement element) {
|
||||
AccessType accessType = null;
|
||||
Access access = element.getAnnotation( Access.class );
|
||||
final Access access = element.getAnnotation( Access.class );
|
||||
if ( access != null ) {
|
||||
accessType = AccessType.getAccessStrategy( access.value() );
|
||||
}
|
||||
|
@ -2160,14 +2177,14 @@ public class EntityBinder {
|
|||
}
|
||||
|
||||
private static void bindFilters(XAnnotatedElement annotatedElement, EntityBinder entityBinder, MetadataBuildingContext context) {
|
||||
Filters filtersAnn = getOverridableAnnotation( annotatedElement, Filters.class, context );
|
||||
final Filters filtersAnn = getOverridableAnnotation( annotatedElement, Filters.class, context );
|
||||
if ( filtersAnn != null ) {
|
||||
for ( Filter filter : filtersAnn.value() ) {
|
||||
entityBinder.addFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
Filter filterAnn = annotatedElement.getAnnotation( Filter.class );
|
||||
final Filter filterAnn = annotatedElement.getAnnotation( Filter.class );
|
||||
if ( filterAnn != null ) {
|
||||
entityBinder.addFilter(filterAnn);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.boot.spi.BootstrapContext;
|
|||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.AccessType;
|
||||
import org.hibernate.cfg.AnnotatedClassType;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumns;
|
||||
import org.hibernate.cfg.AnnotationBinder;
|
||||
import org.hibernate.cfg.CollectionPropertyHolder;
|
||||
import org.hibernate.cfg.CollectionSecondPass;
|
||||
|
@ -102,7 +103,7 @@ public class MapBinder extends CollectionBinder {
|
|||
buildingContext,
|
||||
mapKeyColumns,
|
||||
mapKeyManyToManyColumns,
|
||||
inverseJoinColumns != null ? inverseJoinColumns[0].getPropertyName() : null
|
||||
inverseJoinColumns != null ? inverseJoinColumns.getPropertyName() : null
|
||||
);
|
||||
makeOneToManyMapKeyColumnNullableIfNotInProperty( property );
|
||||
}
|
||||
|
@ -159,7 +160,7 @@ public class MapBinder extends CollectionBinder {
|
|||
boolean isEmbedded,
|
||||
MetadataBuildingContext buildingContext,
|
||||
AnnotatedColumn[] mapKeyColumns,
|
||||
AnnotatedJoinColumn[] mapKeyManyToManyColumns,
|
||||
AnnotatedJoinColumns mapKeyManyToManyColumns,
|
||||
String targetPropertyName) {
|
||||
if ( mapKeyPropertyName != null ) {
|
||||
//this is an EJB3 @MapKey
|
||||
|
@ -340,7 +341,7 @@ public class MapBinder extends CollectionBinder {
|
|||
//FIXME pass the Index Entity JoinColumns
|
||||
if ( !collection.isOneToMany() ) {
|
||||
//index column should not be null
|
||||
for (AnnotatedJoinColumn col : mapKeyManyToManyColumns) {
|
||||
for ( AnnotatedJoinColumn col : mapKeyManyToManyColumns.getColumns() ) {
|
||||
col.forceNotNull();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.boot.model.source.spi.AttributePath;
|
|||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumn;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumns;
|
||||
import org.hibernate.cfg.IndexOrUniqueKeySecondPass;
|
||||
import org.hibernate.cfg.JPAIndexHolder;
|
||||
import org.hibernate.cfg.ObjectNameSource;
|
||||
|
@ -533,26 +534,25 @@ public class TableBinder {
|
|||
public static void bindForeignKey(
|
||||
PersistentClass referencedEntity,
|
||||
PersistentClass destinationEntity,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
SimpleValue value,
|
||||
boolean unique,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final AnnotatedJoinColumn firstColumn = joinColumns[0];
|
||||
|
||||
final PersistentClass associatedClass;
|
||||
if ( destinationEntity != null ) {
|
||||
//overridden destination
|
||||
associatedClass = destinationEntity;
|
||||
}
|
||||
else {
|
||||
final PropertyHolder holder = firstColumn.getPropertyHolder();
|
||||
final PropertyHolder holder = joinColumns.getPropertyHolder();
|
||||
associatedClass = holder == null ? null : holder.getPersistentClass();
|
||||
}
|
||||
|
||||
if ( firstColumn.hasMappedBy() ) {
|
||||
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0];
|
||||
if ( joinColumns.hasMappedBy() ) {
|
||||
// use the columns of the property referenced by mappedBy
|
||||
// copy them and link the copy to the actual value
|
||||
bindUnownedAssociation( joinColumns, value, associatedClass, firstColumn.getMappedBy() );
|
||||
bindUnownedAssociation( joinColumns, value, associatedClass, joinColumns.getMappedBy() );
|
||||
}
|
||||
else if ( firstColumn.isImplicit() ) {
|
||||
// if columns are implicit, then create the columns based
|
||||
|
@ -570,7 +570,7 @@ public class TableBinder {
|
|||
|
||||
private static void bindExplicitColumns(
|
||||
PersistentClass referencedEntity,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
SimpleValue value,
|
||||
MetadataBuildingContext buildingContext,
|
||||
PersistentClass associatedClass) {
|
||||
|
@ -588,16 +588,16 @@ public class TableBinder {
|
|||
|
||||
private static void bindImplicitPrimaryKeyReference(
|
||||
PersistentClass referencedEntity,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
SimpleValue value,
|
||||
PersistentClass associatedClass) {
|
||||
//implicit case, we hope PK and FK columns are in the same order
|
||||
if ( joinColumns.length != referencedEntity.getIdentifier().getColumnSpan() ) {
|
||||
if ( joinColumns.getColumns().length != referencedEntity.getIdentifier().getColumnSpan() ) {
|
||||
// TODO: what about secondary tables?? associatedClass is null?
|
||||
throw new AnnotationException(
|
||||
"An association that targets entity '" + referencedEntity.getEntityName()
|
||||
+ "' from entity '" + associatedClass.getEntityName()
|
||||
+ "' has " + joinColumns.length + " '@JoinColumn's but the primary key has "
|
||||
+ "' has " + joinColumns.getColumns().length + " '@JoinColumn's but the primary key has "
|
||||
+ referencedEntity.getIdentifier().getColumnSpan() + " columns"
|
||||
);
|
||||
}
|
||||
|
@ -614,7 +614,7 @@ public class TableBinder {
|
|||
|
||||
private static void bindPrimaryKeyReference(
|
||||
PersistentClass referencedEntity,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
SimpleValue value,
|
||||
PersistentClass associatedClass,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
|
@ -631,7 +631,7 @@ public class TableBinder {
|
|||
boolean match = false;
|
||||
// for each PK column, find the associated FK column.
|
||||
final String quotedName = column.getQuotedName( dialect );
|
||||
for ( AnnotatedJoinColumn joinColumn : joinColumns ) {
|
||||
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) {
|
||||
final String referencedColumn = buildingContext.getMetadataCollector()
|
||||
.getPhysicalColumnName( referencedEntity.getTable(), joinColumn.getReferencedColumn() );
|
||||
// in JPA 2 referencedColumnName is case-insensitive
|
||||
|
@ -664,14 +664,14 @@ public class TableBinder {
|
|||
|
||||
private static void bindNonPrimaryKeyReference(
|
||||
PersistentClass referencedEntity,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
SimpleValue value) {
|
||||
final String referencedPropertyName;
|
||||
if ( value instanceof ToOne ) {
|
||||
referencedPropertyName = ( (ToOne) value).getReferencedPropertyName();
|
||||
}
|
||||
else if ( value instanceof DependantValue ) {
|
||||
final String propertyName = joinColumns[0].getPropertyName();
|
||||
final String propertyName = joinColumns.getPropertyName();
|
||||
if ( propertyName != null ) {
|
||||
Collection collection = (Collection) referencedEntity.getRecursiveProperty( propertyName ).getValue();
|
||||
referencedPropertyName = collection.getReferencedPropertyName();
|
||||
|
@ -698,25 +698,27 @@ public class TableBinder {
|
|||
|
||||
private static void bindImplicitColumns(
|
||||
PersistentClass referencedEntity,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
SimpleValue value) {
|
||||
final List<Column> idColumns = referencedEntity instanceof JoinedSubclass
|
||||
? referencedEntity.getKey().getColumns()
|
||||
: referencedEntity.getIdentifier().getColumns();
|
||||
for ( Column column: idColumns ) {
|
||||
joinColumns[0].linkValueUsingDefaultColumnNaming( column, referencedEntity, value);
|
||||
joinColumns[0].overrideFromReferencedColumnIfNecessary( column );
|
||||
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0];
|
||||
firstColumn.linkValueUsingDefaultColumnNaming( column, referencedEntity, value);
|
||||
firstColumn.overrideFromReferencedColumnIfNecessary( column );
|
||||
}
|
||||
}
|
||||
|
||||
private static void bindUnownedAssociation(
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
SimpleValue value,
|
||||
PersistentClass associatedClass,
|
||||
String mappedByProperty) {
|
||||
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0];
|
||||
for ( Column column: mappedByColumns( associatedClass, mappedByProperty ) ) {
|
||||
joinColumns[0].overrideFromReferencedColumnIfNecessary( column );
|
||||
joinColumns[0].linkValueUsingAColumnCopy( column, value);
|
||||
firstColumn.overrideFromReferencedColumnIfNecessary( column );
|
||||
firstColumn.linkValueUsingAColumnCopy( column, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -739,19 +741,20 @@ public class TableBinder {
|
|||
public static void linkJoinColumnWithValueOverridingNameIfImplicit(
|
||||
PersistentClass referencedEntity,
|
||||
Value value,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumns joinColumns,
|
||||
SimpleValue simpleValue) {
|
||||
final List<Column> valueColumns = value.getColumns();
|
||||
for ( int i = 0; i < joinColumns.length; i++ ) {
|
||||
final AnnotatedJoinColumn joinCol = joinColumns[i];
|
||||
final AnnotatedJoinColumn[] columns = joinColumns.getColumns();
|
||||
for (int i = 0; i < columns.length; i++ ) {
|
||||
final AnnotatedJoinColumn joinColumn = columns[i];
|
||||
final Column synthCol = valueColumns.get(i);
|
||||
if ( joinCol.isNameDeferred() ) {
|
||||
if ( joinColumn.isNameDeferred() ) {
|
||||
//this has to be the default value
|
||||
joinCol.linkValueUsingDefaultColumnNaming( synthCol, referencedEntity, simpleValue );
|
||||
joinColumn.linkValueUsingDefaultColumnNaming( synthCol, referencedEntity, simpleValue );
|
||||
}
|
||||
else {
|
||||
joinCol.linkWithValue( simpleValue );
|
||||
joinCol.overrideFromReferencedColumnIfNecessary( synthCol );
|
||||
joinColumn.linkWithValue( simpleValue );
|
||||
joinColumn.overrideFromReferencedColumnIfNecessary( synthCol );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -415,7 +415,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
}
|
||||
|
||||
private void checkColumnDuplication() throws MappingException {
|
||||
HashSet<String> cols = new HashSet<>();
|
||||
final HashSet<String> cols = new HashSet<>();
|
||||
checkColumnDuplication( cols, getKey() );
|
||||
if ( isIndexed() ) {
|
||||
checkColumnDuplication(
|
||||
|
|
|
@ -76,10 +76,10 @@ public class ManyToOne extends ToOne {
|
|||
}
|
||||
|
||||
public void createPropertyRefConstraints(Map<String, PersistentClass> persistentClasses) {
|
||||
if (referencedPropertyName!=null) {
|
||||
if ( referencedPropertyName != null ) {
|
||||
// Ensure properties are sorted before we create a foreign key
|
||||
sortProperties();
|
||||
PersistentClass pc = persistentClasses.get(getReferencedEntityName() );
|
||||
PersistentClass pc = persistentClasses.get( getReferencedEntityName() );
|
||||
|
||||
Property property = pc.getReferencedProperty( getReferencedPropertyName() );
|
||||
|
||||
|
|
|
@ -886,7 +886,7 @@ public abstract class SimpleValue implements KeyValue {
|
|||
this.typeParameters = parameterMap;
|
||||
}
|
||||
|
||||
public void setTypeParameters(Map<String, String> parameters) {
|
||||
public void setTypeParameters(Map<String, ? extends Object> parameters) {
|
||||
if ( parameters != null ) {
|
||||
Properties properties = new Properties();
|
||||
properties.putAll( parameters );
|
||||
|
|
|
@ -185,7 +185,7 @@ public class ManyToManyImplicitNamingTest extends BaseNonConfigCoreFunctionalTes
|
|||
);
|
||||
// The default owner and inverse join columns can only be computed if they have PK with 1 column.
|
||||
assertEquals ( 1, ownerCollection.getOwner().getKey().getColumnSpan() );
|
||||
assertEquals( ownerForeignKeyNameExpected, ownerCollection.getKey().getColumnIterator().next().getText() );
|
||||
assertEquals( ownerForeignKeyNameExpected, ownerCollection.getKey().getColumns().get(0).getText() );
|
||||
|
||||
final EntityType associatedEntityType = (EntityType) ownerCollection.getElement().getType();
|
||||
final PersistentClass associatedPersistentClass =
|
||||
|
|
Loading…
Reference in New Issue