HHH-7983 : RelationalValueBindingContainer
This commit is contained in:
parent
974e43a5fb
commit
1634d56c36
|
@ -203,12 +203,14 @@ public class Binder {
|
|||
private final LinkedList<InheritanceType> inheritanceTypes = new LinkedList<InheritanceType>();
|
||||
private final LinkedList<EntityMode> entityModes = new LinkedList<EntityMode>();
|
||||
private final HibernateTypeHelper typeHelper; // todo: refactor helper and remove redundant methods in this class
|
||||
private final ForeignKeyHelper foreignKeyHelper;
|
||||
|
||||
public Binder(final MetadataImplementor metadata,
|
||||
final IdentifierGeneratorFactory identifierGeneratorFactory) {
|
||||
this.metadata = metadata;
|
||||
this.identifierGeneratorFactory = identifierGeneratorFactory;
|
||||
this.typeHelper = new HibernateTypeHelper( this, metadata );
|
||||
this.foreignKeyHelper = new ForeignKeyHelper( this );
|
||||
this.nameNormalizer = metadata.getObjectNameNormalizer();
|
||||
}
|
||||
|
||||
|
@ -678,9 +680,9 @@ public class Binder {
|
|||
);
|
||||
|
||||
// TODO: make the foreign key column the primary key???
|
||||
final ForeignKey foreignKey = bindForeignKey(
|
||||
final ForeignKey foreignKey = locateOrCreateForeignKey(
|
||||
quotedIdentifier( secondaryTableSource.getExplicitForeignKeyName() ),
|
||||
extractColumnsFromRelationalValueBindings( joinRelationalValueBindings ),
|
||||
joinRelationalValueBindings,
|
||||
determineForeignKeyTargetColumns( entityBinding, secondaryTableSource )
|
||||
);
|
||||
SecondaryTable secondaryTable = new SecondaryTable( table, foreignKey );
|
||||
|
@ -692,6 +694,34 @@ public class Binder {
|
|||
}
|
||||
}
|
||||
|
||||
public ForeignKey locateOrCreateForeignKey(
|
||||
final String foreignKeyName,
|
||||
final List<RelationalValueBinding> sourceRelationalValueBindings,
|
||||
final List<Column> targetColumns) {
|
||||
return foreignKeyHelper.locateOrCreateForeignKey(
|
||||
foreignKeyName,
|
||||
extractColumnsFromRelationalValueBindings( sourceRelationalValueBindings ),
|
||||
targetColumns
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: try to get rid of this...
|
||||
private static List<Column> extractColumnsFromRelationalValueBindings(
|
||||
final List<RelationalValueBinding> valueBindings) {
|
||||
List<Column> columns = new ArrayList<Column>( valueBindings.size() );
|
||||
for ( RelationalValueBinding relationalValueBinding : valueBindings ) {
|
||||
final Value value = relationalValueBinding.getValue();
|
||||
// todo : currently formulas are not supported here... :(
|
||||
if ( !Column.class.isInstance( value ) ) {
|
||||
throw new NotYetImplementedException(
|
||||
"Derived values are not supported when creating a foreign key that targets columns."
|
||||
);
|
||||
}
|
||||
columns.add( (Column) value );
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ identifier binding relates methods
|
||||
private void bindIdentifier(
|
||||
final EntityBinding rootEntityBinding,
|
||||
|
@ -1159,10 +1189,10 @@ public class Binder {
|
|||
attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping(),
|
||||
attributeBinding.getRelationalValueBindings()
|
||||
);
|
||||
if ( !hasDerivedValue( attributeBinding.getRelationalValueBindings() ) ) {
|
||||
bindForeignKey(
|
||||
if ( !attributeBinding.hasDerivedValue() ) {
|
||||
locateOrCreateForeignKey(
|
||||
quotedIdentifier( attributeSource.getExplicitForeignKeyName() ),
|
||||
extractColumnsFromRelationalValueBindings( attributeBinding.getRelationalValueBindings() ),
|
||||
attributeBinding.getRelationalValueBindings(),
|
||||
determineForeignKeyTargetColumns(
|
||||
attributeBinding.getReferencedEntityBinding(),
|
||||
attributeSource
|
||||
|
@ -1271,19 +1301,18 @@ public class Binder {
|
|||
toOneAttributeBindingContext
|
||||
);
|
||||
if ( attributeSource.getForeignKeyDirection() == ForeignKeyDirection.FROM_PARENT ) {
|
||||
List<Column> foreignKeyColumns = extractColumnsFromRelationalValueBindings(
|
||||
List<RelationalValueBinding> foreignKeyRelationalValueBindings =
|
||||
attributeBinding
|
||||
.getContainer()
|
||||
.seekEntityBinding()
|
||||
.getHierarchyDetails()
|
||||
.getEntityIdentifier()
|
||||
.getAttributeBinding()
|
||||
.getRelationalValueBindings()
|
||||
);
|
||||
.getRelationalValueBindings();
|
||||
|
||||
bindForeignKey(
|
||||
locateOrCreateForeignKey(
|
||||
quotedIdentifier( attributeSource.getExplicitForeignKeyName() ),
|
||||
foreignKeyColumns,
|
||||
foreignKeyRelationalValueBindings,
|
||||
determineForeignKeyTargetColumns(
|
||||
attributeBinding.getReferencedEntityBinding(),
|
||||
attributeSource
|
||||
|
@ -1865,10 +1894,10 @@ public class Binder {
|
|||
);
|
||||
|
||||
if ( !elementBinding.getPluralAttributeBinding().getPluralAttributeKeyBinding().isInverse() &&
|
||||
!hasDerivedValue( elementBinding.getRelationalValueBindings() ) ) {
|
||||
bindForeignKey(
|
||||
!elementBinding.hasDerivedValue() ) {
|
||||
locateOrCreateForeignKey(
|
||||
quotedIdentifier( elementSource.getExplicitForeignKeyName() ),
|
||||
extractColumnsFromRelationalValueBindings( elementBinding.getRelationalValueBindings() ),
|
||||
elementBinding.getRelationalValueBindings(),
|
||||
targetColumns
|
||||
);
|
||||
}
|
||||
|
@ -1927,7 +1956,6 @@ public class Binder {
|
|||
referencedAttributeBinding.getReferencedAttributeBinding()
|
||||
.getHibernateTypeDescriptor()
|
||||
);
|
||||
boolean isUpdatable = false;
|
||||
List<RelationalValueBinding> sourceColumnBindings = referencedAttributeBinding.getRelationalValueBindings();
|
||||
List<Column> sourceColumns = new ArrayList<Column>();
|
||||
for ( RelationalValueBinding relationalValueBinding : sourceColumnBindings ) {
|
||||
|
@ -1935,14 +1963,13 @@ public class Binder {
|
|||
if ( Column.class.isInstance( v ) ) {
|
||||
sourceColumns.add( Column.class.cast( v ) );
|
||||
}
|
||||
isUpdatable = isUpdatable || relationalValueBinding.isIncludeInUpdate();
|
||||
}
|
||||
for ( ForeignKey fk : referencedEntityBinding.getPrimaryTable().getForeignKeys() ) {
|
||||
if ( fk.getSourceColumns().equals( sourceColumns ) ) {
|
||||
keyBinding.setForeignKey( fk );
|
||||
keyBinding.setCascadeDeleteEnabled( fk.getDeleteRule() == ForeignKey.ReferentialAction.CASCADE );
|
||||
}
|
||||
}
|
||||
keyBinding.setUpdatable( isUpdatable );
|
||||
keyBinding.setRelationalValueBindings( sourceColumnBindings );
|
||||
}
|
||||
else {
|
||||
bindCollectionTableForeignKey( attributeBinding, attributeSource.getKeySource(), collectionTable );
|
||||
|
@ -2300,7 +2327,7 @@ public class Binder {
|
|||
)
|
||||
);
|
||||
}
|
||||
if ( hasAnyNonNullableColumns( elementBinding.getRelationalValueBindings() ) ) {
|
||||
if ( elementBinding.hasNonNullableValue() ) {
|
||||
bindSetCollectionTablePrimaryKey( attributeBinding );
|
||||
}
|
||||
else {
|
||||
|
@ -2315,9 +2342,10 @@ public class Binder {
|
|||
final PrimaryKey primaryKey = attributeBinding.getPluralAttributeKeyBinding()
|
||||
.getCollectionTable()
|
||||
.getPrimaryKey();
|
||||
final ForeignKey foreignKey = attributeBinding.getPluralAttributeKeyBinding().getForeignKey();
|
||||
for ( final Column foreignKeyColumn : foreignKey.getSourceColumns() ) {
|
||||
primaryKey.addColumn( foreignKeyColumn );
|
||||
final List<RelationalValueBinding> keyValueBindings =
|
||||
attributeBinding.getPluralAttributeKeyBinding().getRelationalValueBindings();
|
||||
for ( final RelationalValueBinding keyRelationalValueBinding : keyValueBindings ) {
|
||||
primaryKey.addColumn( (Column) keyRelationalValueBinding.getValue() );
|
||||
}
|
||||
for ( final RelationalValueBinding elementValueBinding : elementBinding.getRelationalValueBindings() ) {
|
||||
if ( !elementValueBinding.isDerived() && !elementValueBinding.isNullable() ) {
|
||||
|
@ -2357,7 +2385,7 @@ public class Binder {
|
|||
);
|
||||
}
|
||||
|
||||
List<RelationalValueBinding> sourceColumnBindings =
|
||||
List<RelationalValueBinding> sourceRelationalBindings =
|
||||
bindValues(
|
||||
attributeBindingContainer,
|
||||
keySource,
|
||||
|
@ -2367,33 +2395,14 @@ public class Binder {
|
|||
attributeBinding.getPluralAttributeElementBinding()
|
||||
.getNature() != PluralAttributeElementBinding.Nature.ONE_TO_MANY
|
||||
);
|
||||
// Determine if the foreign key (source) column is updatable and also extract the columns out
|
||||
// of the RelationalValueBindings.
|
||||
boolean isInsertable = false;
|
||||
boolean isUpdatable = false;
|
||||
List<Column> sourceColumns = new ArrayList<Column>( sourceColumnBindings.size() );
|
||||
for ( RelationalValueBinding relationalValueBinding : sourceColumnBindings ) {
|
||||
final Value value = relationalValueBinding.getValue();
|
||||
// todo : currently formulas are not supported here... :(
|
||||
if ( !Column.class.isInstance( value ) ) {
|
||||
throw new NotYetImplementedException(
|
||||
"Derived values are not supported when creating a foreign key that targets columns."
|
||||
);
|
||||
}
|
||||
isInsertable = isInsertable || relationalValueBinding.isIncludeInInsert();
|
||||
isUpdatable = isUpdatable || relationalValueBinding.isIncludeInUpdate();
|
||||
sourceColumns.add( (Column) value );
|
||||
}
|
||||
keyBinding.setInsertable( isInsertable );
|
||||
keyBinding.setUpdatable( isUpdatable );
|
||||
|
||||
ForeignKey foreignKey = bindForeignKey(
|
||||
keyBinding.setRelationalValueBindings( sourceRelationalBindings );
|
||||
ForeignKey foreignKey = locateOrCreateForeignKey(
|
||||
quotedIdentifier( keySource.getExplicitForeignKeyName() ),
|
||||
sourceColumns,
|
||||
sourceRelationalBindings,
|
||||
targetColumns
|
||||
);
|
||||
foreignKey.setDeleteRule( keySource.getOnDeleteAction() );
|
||||
keyBinding.setForeignKey( foreignKey );
|
||||
keyBinding.setCascadeDeleteEnabled( keySource.getOnDeleteAction() == ForeignKey.ReferentialAction.CASCADE );
|
||||
final HibernateTypeDescriptor pluralAttributeKeyTypeDescriptor = keyBinding.getHibernateTypeDescriptor();
|
||||
|
||||
pluralAttributeKeyTypeDescriptor.copyFrom(
|
||||
|
@ -2402,15 +2411,15 @@ public class Binder {
|
|||
);
|
||||
final Type resolvedKeyType = pluralAttributeKeyTypeDescriptor.getResolvedTypeMapping();
|
||||
|
||||
Iterator<Column> fkColumnIterator = keyBinding.getForeignKey().getSourceColumns().iterator();
|
||||
Iterator<RelationalValueBinding> fkColumnIterator = keyBinding.getRelationalValueBindings().iterator();
|
||||
if ( resolvedKeyType.isComponentType() ) {
|
||||
ComponentType componentType = (ComponentType) resolvedKeyType;
|
||||
for ( Type subType : componentType.getSubtypes() ) {
|
||||
typeHelper.bindJdbcDataType( subType, fkColumnIterator.next() );
|
||||
typeHelper.bindJdbcDataType( subType, fkColumnIterator.next().getValue() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
typeHelper.bindJdbcDataType( resolvedKeyType, fkColumnIterator.next() );
|
||||
typeHelper.bindJdbcDataType( resolvedKeyType, fkColumnIterator.next().getValue() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2522,7 +2531,7 @@ public class Binder {
|
|||
subclassEntitySource
|
||||
);
|
||||
|
||||
ForeignKey foreignKey = bindForeignKey(
|
||||
ForeignKey foreignKey = foreignKeyHelper.locateOrCreateForeignKey(
|
||||
quotedIdentifier( subclassEntitySource.getExplicitForeignKeyName() ),
|
||||
sourceColumns,
|
||||
targetColumns
|
||||
|
@ -2538,64 +2547,6 @@ public class Binder {
|
|||
}
|
||||
|
||||
|
||||
private ForeignKey bindForeignKey(
|
||||
final String foreignKeyName,
|
||||
final List<Column> sourceColumns,
|
||||
final List<Column> targetColumns) {
|
||||
ForeignKey foreignKey = null;
|
||||
if ( foreignKeyName != null ) {
|
||||
foreignKey = locateAndBindForeignKeyByName( foreignKeyName, sourceColumns, targetColumns );
|
||||
}
|
||||
if ( foreignKey == null ) {
|
||||
foreignKey = locateForeignKeyByColumnMapping( sourceColumns, targetColumns );
|
||||
if ( foreignKey != null && foreignKeyName != null ) {
|
||||
if ( foreignKey.getName() == null ) {
|
||||
// the foreign key name has not be initialized; set it to foreignKeyName
|
||||
foreignKey.setName( foreignKeyName );
|
||||
}
|
||||
else {
|
||||
// the foreign key name has already been initialized so cannot rename it
|
||||
// TODO: should this just be INFO?
|
||||
log.warn(
|
||||
String.format(
|
||||
"A foreign key mapped as %s will not be created because foreign key %s already exists with the same column mapping.",
|
||||
foreignKeyName,
|
||||
foreignKey.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( foreignKey == null ) {
|
||||
// no foreign key found; create one
|
||||
final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable();
|
||||
final TableSpecification targetTable = targetColumns.get( 0 ).getTable();
|
||||
foreignKey = sourceTable.createForeignKey( targetTable, foreignKeyName );
|
||||
bindForeignKeyColumns( foreignKey, sourceColumns, targetColumns );
|
||||
}
|
||||
return foreignKey;
|
||||
}
|
||||
|
||||
private void bindForeignKeyColumns(
|
||||
final ForeignKey foreignKey,
|
||||
final List<Column> sourceColumns,
|
||||
final List<Column> targetColumns) {
|
||||
if ( sourceColumns.size() != targetColumns.size() ) {
|
||||
throw bindingContext().makeMappingException(
|
||||
String.format(
|
||||
"Non-matching number columns in foreign key source columns [%s : %s] and target columns [%s : %s]",
|
||||
sourceColumns.get( 0 ).getTable().getLogicalName().getText(),
|
||||
sourceColumns.size(),
|
||||
targetColumns.get( 0 ).getTable().getLogicalName().getText(),
|
||||
targetColumns.size()
|
||||
)
|
||||
);
|
||||
}
|
||||
for ( int i = 0; i < sourceColumns.size(); i++ ) {
|
||||
foreignKey.addColumnMapping( sourceColumns.get( i ), targetColumns.get( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
private TableSpecification locateDefaultTableSpecificationForAttribute(
|
||||
final AttributeBindingContainer attributeBindingContainer,
|
||||
final SingularAttributeSource attributeSource) {
|
||||
|
@ -2771,7 +2722,7 @@ public class Binder {
|
|||
new ColumnNamingStrategyHelper( defaultName, isDefaultAttributeName )
|
||||
);
|
||||
final Column column = table.locateOrCreateColumn( resolvedColumnName );
|
||||
resolveColumnNullabl( columnSource, forceNotNull, isNullableByDefault, column );
|
||||
resolveColumnNullable( columnSource, forceNotNull, isNullableByDefault, column );
|
||||
column.setDefaultValue( columnSource.getDefaultValue() );
|
||||
column.setSqlType( columnSource.getSqlType() );
|
||||
column.setSize( columnSource.getSize() );
|
||||
|
@ -2784,7 +2735,7 @@ public class Binder {
|
|||
return column;
|
||||
}
|
||||
|
||||
private void resolveColumnNullabl(
|
||||
private void resolveColumnNullable(
|
||||
final ColumnSource columnSource,
|
||||
final boolean forceNotNull,
|
||||
final boolean isNullableByDefault,
|
||||
|
@ -2958,50 +2909,6 @@ public class Binder {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private ForeignKey locateAndBindForeignKeyByName(
|
||||
final String foreignKeyName,
|
||||
final List<Column> sourceColumns,
|
||||
final List<Column> targetColumns) {
|
||||
if ( foreignKeyName == null ) {
|
||||
throw new AssertionFailure( "foreignKeyName must be non-null." );
|
||||
}
|
||||
final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable();
|
||||
final TableSpecification targetTable = targetColumns.get( 0 ).getTable();
|
||||
ForeignKey foreignKey = sourceTable.locateForeignKey( foreignKeyName );
|
||||
if ( foreignKey != null ) {
|
||||
if ( !targetTable.equals( foreignKey.getTargetTable() ) ) {
|
||||
throw bindingContext().makeMappingException(
|
||||
String.format(
|
||||
"Unexpected target table defined for foreign key \"%s\"; expected \"%s\"; found \"%s\"",
|
||||
foreignKeyName,
|
||||
targetTable.getLogicalName(),
|
||||
foreignKey.getTargetTable().getLogicalName()
|
||||
)
|
||||
);
|
||||
}
|
||||
// check if source and target columns have been bound already
|
||||
if ( foreignKey.getColumnSpan() == 0 ) {
|
||||
// foreign key was found, but no columns bound to it yet
|
||||
bindForeignKeyColumns( foreignKey, sourceColumns, targetColumns );
|
||||
}
|
||||
else {
|
||||
// The located foreign key already has columns bound;
|
||||
// Make sure they are the same columns.
|
||||
if ( !foreignKey.getSourceColumns().equals( sourceColumns ) ||
|
||||
foreignKey.getTargetColumns().equals( targetColumns ) ) {
|
||||
throw bindingContext().makeMappingException(
|
||||
String.format(
|
||||
"Attempt to bind exisitng foreign key \"%s\" with different columns.",
|
||||
foreignKeyName
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return foreignKey;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ simple instance helper methods
|
||||
private void mapSourcesByName(final EntitySource rootEntitySource) {
|
||||
String entityName = rootEntitySource.getEntityName();
|
||||
|
@ -3086,10 +2993,11 @@ public class Binder {
|
|||
final PrimaryKey primaryKey = attributeBinding.getPluralAttributeKeyBinding()
|
||||
.getCollectionTable()
|
||||
.getPrimaryKey();
|
||||
final ForeignKey foreignKey = attributeBinding.getPluralAttributeKeyBinding().getForeignKey();
|
||||
final List<RelationalValueBinding> keyRelationalValueBindings =
|
||||
attributeBinding.getPluralAttributeKeyBinding().getRelationalValueBindings();
|
||||
final PluralAttributeIndexBinding indexBinding = attributeBinding.getPluralAttributeIndexBinding();
|
||||
for ( final Column foreignKeyColumn : foreignKey.getSourceColumns() ) {
|
||||
primaryKey.addColumn( foreignKeyColumn );
|
||||
for ( final RelationalValueBinding keyRelationalValueBinding : keyRelationalValueBindings ) {
|
||||
primaryKey.addColumn( (Column) keyRelationalValueBinding.getValue() );
|
||||
}
|
||||
for ( RelationalValueBinding relationalValueBinding : indexBinding.getRelationalValueBindings() ) {
|
||||
if ( !relationalValueBinding.isDerived() ) {
|
||||
|
@ -3122,16 +3030,6 @@ public class Binder {
|
|||
return fullPath.substring( attributeBinding.getContainer().seekEntityBinding().getEntityName().length() + 1 );
|
||||
}
|
||||
|
||||
private static boolean hasDerivedValue(
|
||||
final List<RelationalValueBinding> relationalValueBindings) {
|
||||
for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) {
|
||||
if ( DerivedValue.class.isInstance( relationalValueBinding.getValue() ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: should this be moved to CascadeStyles as a static method?
|
||||
// TODO: sources already factor in default cascade; should that be done here instead?
|
||||
private static CascadeStyle determineCascadeStyle(
|
||||
|
@ -3203,60 +3101,12 @@ public class Binder {
|
|||
.createSingularAttribute( attributeSource.getName() );
|
||||
}
|
||||
|
||||
private static ForeignKey locateForeignKeyByColumnMapping(
|
||||
final List<Column> sourceColumns,
|
||||
final List<Column> targetColumns) {
|
||||
final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable();
|
||||
final TableSpecification targetTable = targetColumns.get( 0 ).getTable();
|
||||
// check for an existing foreign key with the same source/target columns
|
||||
ForeignKey foreignKey = null;
|
||||
Iterable<ForeignKey> possibleForeignKeys = sourceTable.locateForeignKey( targetTable );
|
||||
if ( possibleForeignKeys != null ) {
|
||||
for ( ForeignKey possibleFK : possibleForeignKeys ) {
|
||||
if ( possibleFK.getSourceColumns().equals( sourceColumns ) &&
|
||||
possibleFK.getTargetColumns().equals( targetColumns ) ) {
|
||||
// this is the foreign key
|
||||
foreignKey = possibleFK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return foreignKey;
|
||||
}
|
||||
|
||||
private static String attributeSourcesByNameKey(
|
||||
final String entityName,
|
||||
final String attributeName) {
|
||||
return entityName + "." + attributeName;
|
||||
}
|
||||
|
||||
// TODO: try to get rid of this...
|
||||
private static List<Column> extractColumnsFromRelationalValueBindings(
|
||||
final List<RelationalValueBinding> valueBindings) {
|
||||
List<Column> columns = new ArrayList<Column>( valueBindings.size() );
|
||||
for ( RelationalValueBinding relationalValueBinding : valueBindings ) {
|
||||
final Value value = relationalValueBinding.getValue();
|
||||
// todo : currently formulas are not supported here... :(
|
||||
if ( !Column.class.isInstance( value ) ) {
|
||||
throw new NotYetImplementedException(
|
||||
"Derived values are not supported when creating a foreign key that targets columns."
|
||||
);
|
||||
}
|
||||
columns.add( (Column) value );
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
private static boolean hasAnyNonNullableColumns(
|
||||
final List<RelationalValueBinding> relationalValueBindings) {
|
||||
for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) {
|
||||
if ( Column.class.isInstance( relationalValueBinding.getValue() ) && !relationalValueBinding.isNullable() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static String createAttributePath(
|
||||
final AttributeBinding attributeBinding) {
|
||||
return attributeBinding.getContainer().getPathBase() + '.' + attributeBinding.getAttribute().getName();
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.metamodel.spi.relational.Column;
|
||||
import org.hibernate.metamodel.spi.relational.ForeignKey;
|
||||
import org.hibernate.metamodel.spi.relational.TableSpecification;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class ForeignKeyHelper {
|
||||
private static final CoreMessageLogger log = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
ForeignKeyHelper.class.getName()
|
||||
);
|
||||
|
||||
private final Binder binder;
|
||||
|
||||
public ForeignKeyHelper(Binder binder) {
|
||||
this.binder = binder;
|
||||
}
|
||||
|
||||
public ForeignKey locateOrCreateForeignKey(
|
||||
final String foreignKeyName,
|
||||
final List<Column> sourceColumns,
|
||||
final List<Column> targetColumns) {
|
||||
ForeignKey foreignKey = null;
|
||||
if ( foreignKeyName != null ) {
|
||||
foreignKey = locateAndBindForeignKeyByName( foreignKeyName, sourceColumns, targetColumns );
|
||||
}
|
||||
if ( foreignKey == null ) {
|
||||
foreignKey = locateForeignKeyByColumnMapping( sourceColumns, targetColumns );
|
||||
if ( foreignKey != null && foreignKeyName != null ) {
|
||||
if ( foreignKey.getName() == null ) {
|
||||
// the foreign key name has not be initialized; set it to foreignKeyName
|
||||
foreignKey.setName( foreignKeyName );
|
||||
}
|
||||
else {
|
||||
// the foreign key name has already been initialized so cannot rename it
|
||||
// TODO: should this just be INFO?
|
||||
log.warn(
|
||||
String.format(
|
||||
"A foreign key mapped as %s will not be created because foreign key %s already exists with the same column mapping.",
|
||||
foreignKeyName,
|
||||
foreignKey.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( foreignKey == null ) {
|
||||
// no foreign key found; create one
|
||||
final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable();
|
||||
final TableSpecification targetTable = targetColumns.get( 0 ).getTable();
|
||||
foreignKey = sourceTable.createForeignKey( targetTable, foreignKeyName );
|
||||
bindForeignKeyColumns( foreignKey, sourceColumns, targetColumns );
|
||||
}
|
||||
return foreignKey;
|
||||
}
|
||||
|
||||
private static ForeignKey locateForeignKeyByColumnMapping(
|
||||
final List<Column> sourceColumns,
|
||||
final List<Column> targetColumns) {
|
||||
final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable();
|
||||
final TableSpecification targetTable = targetColumns.get( 0 ).getTable();
|
||||
// check for an existing foreign key with the same source/target columns
|
||||
ForeignKey foreignKey = null;
|
||||
Iterable<ForeignKey> possibleForeignKeys = sourceTable.locateForeignKey( targetTable );
|
||||
if ( possibleForeignKeys != null ) {
|
||||
for ( ForeignKey possibleFK : possibleForeignKeys ) {
|
||||
if ( possibleFK.getSourceColumns().equals( sourceColumns ) &&
|
||||
possibleFK.getTargetColumns().equals( targetColumns ) ) {
|
||||
// this is the foreign key
|
||||
foreignKey = possibleFK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return foreignKey;
|
||||
}
|
||||
|
||||
private void bindForeignKeyColumns(
|
||||
final ForeignKey foreignKey,
|
||||
final List<Column> sourceColumns,
|
||||
final List<Column> targetColumns) {
|
||||
if ( sourceColumns.size() != targetColumns.size() ) {
|
||||
throw binder.bindingContext().makeMappingException(
|
||||
String.format(
|
||||
"Non-matching number columns in foreign key source columns [%s : %s] and target columns [%s : %s]",
|
||||
sourceColumns.get( 0 ).getTable().getLogicalName().getText(),
|
||||
sourceColumns.size(),
|
||||
targetColumns.get( 0 ).getTable().getLogicalName().getText(),
|
||||
targetColumns.size()
|
||||
)
|
||||
);
|
||||
}
|
||||
for ( int i = 0; i < sourceColumns.size(); i++ ) {
|
||||
foreignKey.addColumnMapping( sourceColumns.get( i ), targetColumns.get( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
private ForeignKey locateAndBindForeignKeyByName(
|
||||
final String foreignKeyName,
|
||||
final List<Column> sourceColumns,
|
||||
final List<Column> targetColumns) {
|
||||
if ( foreignKeyName == null ) {
|
||||
throw new AssertionFailure( "foreignKeyName must be non-null." );
|
||||
}
|
||||
final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable();
|
||||
final TableSpecification targetTable = targetColumns.get( 0 ).getTable();
|
||||
ForeignKey foreignKey = sourceTable.locateForeignKey( foreignKeyName );
|
||||
if ( foreignKey != null ) {
|
||||
if ( !targetTable.equals( foreignKey.getTargetTable() ) ) {
|
||||
throw binder.bindingContext().makeMappingException(
|
||||
String.format(
|
||||
"Unexpected target table defined for foreign key \"%s\"; expected \"%s\"; found \"%s\"",
|
||||
foreignKeyName,
|
||||
targetTable.getLogicalName(),
|
||||
foreignKey.getTargetTable().getLogicalName()
|
||||
)
|
||||
);
|
||||
}
|
||||
// check if source and target columns have been bound already
|
||||
if ( foreignKey.getColumnSpan() == 0 ) {
|
||||
// foreign key was found, but no columns bound to it yet
|
||||
bindForeignKeyColumns( foreignKey, sourceColumns, targetColumns );
|
||||
}
|
||||
else {
|
||||
// The located foreign key already has columns bound;
|
||||
// Make sure they are the same columns.
|
||||
if ( !foreignKey.getSourceColumns().equals( sourceColumns ) ||
|
||||
foreignKey.getTargetColumns().equals( targetColumns ) ) {
|
||||
throw binder.bindingContext().makeMappingException(
|
||||
String.format(
|
||||
"Attempt to bind exisitng foreign key \"%s\" with different columns.",
|
||||
foreignKeyName
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return foreignKey;
|
||||
}
|
||||
}
|
|
@ -408,7 +408,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
|
|||
entityBindingMap.get(
|
||||
pluralAttributeBinding.getPluralAttributeElementBinding().getHibernateTypeDescriptor().
|
||||
getResolvedTypeMapping().getName() );
|
||||
List<Column> columns = keyBinding.getForeignKey().getColumns();
|
||||
List<RelationalValueBinding> keyValueBindings = keyBinding.getRelationalValueBindings();
|
||||
boolean bidirectional = false;
|
||||
for ( AttributeBinding attributeBinding : referencedEntityBinding.attributeBindings() ) {
|
||||
if ( !(attributeBinding instanceof ManyToOneAttributeBinding) ) {
|
||||
|
@ -423,12 +423,12 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
|
|||
// Check if the many-to-one attribute binding's columns match the one-to-many attribute binding's FK columns
|
||||
// (meaning this is a bidirectional association, and no back reference should be created)
|
||||
List<RelationalValueBinding> valueBindings = manyToOneAttributeBinding.getRelationalValueBindings();
|
||||
if ( columns.size() != valueBindings.size() ) {
|
||||
if ( keyValueBindings.size() != valueBindings.size() ) {
|
||||
continue;
|
||||
}
|
||||
bidirectional = true;
|
||||
for ( int ndx = valueBindings.size(); --ndx >= 0; ) {
|
||||
if ( columns.get(ndx) != valueBindings.get( ndx ).getValue() ) {
|
||||
if ( keyValueBindings.get(ndx) != valueBindings.get( ndx ) ) {
|
||||
bidirectional = false;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ public class CompositePluralAttributeIndexSourceImpl
|
|||
|
||||
@Override
|
||||
public boolean areValuesIncludedInUpdateByDefault() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -131,7 +131,7 @@ public class SequentialPluralAttributeIndexSourceImpl extends AbstractHbmSourceN
|
|||
|
||||
@Override
|
||||
public boolean areValuesIncludedInUpdateByDefault() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -100,6 +100,12 @@ public abstract class AbstractCompositeAttributeBindingContainer
|
|||
|
||||
protected abstract boolean isModifiable();
|
||||
|
||||
protected RelationalValueBindingContainer getRelationalValueBindingContainer() {
|
||||
final RelationalValueBindingContainer bindingContainer = new RelationalValueBindingContainer();
|
||||
collectRelationalValueBindings( bindingContainer );
|
||||
return bindingContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicAttributeBinding makeBasicAttributeBinding(
|
||||
SingularAttribute attribute,
|
||||
|
|
|
@ -48,4 +48,26 @@ public abstract class AbstractPluralAttributeElementBinding implements PluralAtt
|
|||
public HibernateTypeDescriptor getHibernateTypeDescriptor() {
|
||||
return hibernateTypeDescriptor;
|
||||
}
|
||||
|
||||
protected abstract RelationalValueBindingContainer getRelationalValueContainer();
|
||||
|
||||
@Override
|
||||
public List<RelationalValueBinding> getRelationalValueBindings() {
|
||||
return getRelationalValueContainer().relationalValueBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullable() {
|
||||
return getRelationalValueContainer().hasNullableRelationalValueBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDerivedValue() {
|
||||
return getRelationalValueContainer().hasDerivedValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNonNullableValue() {
|
||||
return getRelationalValueContainer().hasNonNullableRelationalValueBinding();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ import org.hibernate.metamodel.spi.source.MetaAttributeContext;
|
|||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class AbstractSingularAssociationAttributeBinding extends AbstractSingularAttributeBinding
|
||||
public abstract class AbstractSingularAssociationAttributeBinding extends AbstractSingularAttributeBinding
|
||||
implements SingularAssociationAttributeBinding {
|
||||
protected final EntityBinding referencedEntityBinding;
|
||||
protected final SingularAttributeBinding referencedAttributeBinding;
|
||||
|
@ -85,12 +85,6 @@ public class AbstractSingularAssociationAttributeBinding extends AbstractSingula
|
|||
return isNotFoundAnException;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDerivedValue() {
|
||||
// TODO: support derived value
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssociation() {
|
||||
return true;
|
||||
|
@ -166,6 +160,6 @@ public class AbstractSingularAssociationAttributeBinding extends AbstractSingula
|
|||
|
||||
@Override
|
||||
protected void collectRelationalValueBindings(RelationalValueBindingContainer relationalValueBindingContainer) {
|
||||
relationalValueBindingContainer.addRelationalValueBindings( this.relationalValueBindingContainer);
|
||||
relationalValueBindingContainer.addRelationalValueBindings( this.relationalValueBindingContainer );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,9 +58,14 @@ public abstract class AbstractSingularAttributeBinding
|
|||
return getRelationalValueBindingContainer().relationalValueBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDerivedValue() {
|
||||
return getRelationalValueBindingContainer().hasDerivedValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullable() {
|
||||
return getRelationalValueBindingContainer().hasNullableRelationalValueBinding();
|
||||
return !getRelationalValueBindingContainer().hasNonNullableRelationalValueBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -70,8 +70,9 @@ public class BackRefAttributeBinding extends BasicAttributeBinding {
|
|||
}
|
||||
else {
|
||||
relationalValueBindings = new ArrayList<RelationalValueBinding>( );
|
||||
for ( Column column : pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey().getSourceColumns() ) {
|
||||
relationalValueBindings.add( new RelationalValueBinding( column, true, false ) );
|
||||
for ( RelationalValueBinding keyRelationalValueBindings : pluralAttributeBinding.getPluralAttributeKeyBinding().getRelationalValueBindings() ) {
|
||||
Column keyColumn = (Column) keyRelationalValueBindings.getValue();
|
||||
relationalValueBindings.add( new RelationalValueBinding( keyColumn, true, false ) );
|
||||
}
|
||||
}
|
||||
return relationalValueBindings;
|
||||
|
@ -99,18 +100,9 @@ public class BackRefAttributeBinding extends BasicAttributeBinding {
|
|||
return isIndexBackRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDerivedValue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncludedInUpdate() {
|
||||
//TODO: should be able to rely on super method, but that seems broken currently.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.spi.binding;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.mapping.PropertyGeneration;
|
||||
|
@ -40,7 +39,6 @@ public class BasicAttributeBinding
|
|||
implements SingularNonAssociationAttributeBinding {
|
||||
|
||||
private final RelationalValueBindingContainer relationalValueBindingContainer;
|
||||
private boolean hasDerivedValue;
|
||||
private final PropertyGeneration generation;
|
||||
|
||||
BasicAttributeBinding(
|
||||
|
@ -62,11 +60,7 @@ public class BasicAttributeBinding
|
|||
naturalIdMutability,
|
||||
metaAttributeContext
|
||||
);
|
||||
this.relationalValueBindingContainer =
|
||||
new RelationalValueBindingContainer( relationalValueBindings );
|
||||
for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) {
|
||||
this.hasDerivedValue = this.hasDerivedValue || relationalValueBinding.isDerived();
|
||||
}
|
||||
this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings );
|
||||
this.generation = generation;
|
||||
}
|
||||
|
||||
|
@ -75,15 +69,6 @@ public class BasicAttributeBinding
|
|||
return false;
|
||||
}
|
||||
|
||||
public List<RelationalValueBinding> getRelationalValueBindings() {
|
||||
return relationalValueBindingContainer.relationalValueBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDerivedValue() {
|
||||
return hasDerivedValue;
|
||||
}
|
||||
|
||||
public PropertyGeneration getGeneration() {
|
||||
return generation;
|
||||
}
|
||||
|
|
|
@ -34,29 +34,23 @@ import java.util.List;
|
|||
*/
|
||||
public class BasicPluralAttributeElementBinding extends AbstractPluralAttributeElementBinding {
|
||||
|
||||
private boolean hasDerivedValue;
|
||||
private boolean isNullable = true;
|
||||
private List<RelationalValueBinding> relationalValueBindings;
|
||||
private RelationalValueBindingContainer relationalValueBindingContainer;
|
||||
|
||||
public BasicPluralAttributeElementBinding(AbstractPluralAttributeBinding binding) {
|
||||
super( binding );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RelationalValueBindingContainer getRelationalValueContainer() {
|
||||
return relationalValueBindingContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return Nature.BASIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RelationalValueBinding> getRelationalValueBindings() {
|
||||
return relationalValueBindings;
|
||||
}
|
||||
|
||||
public void setRelationalValueBindings(List<RelationalValueBinding> relationalValueBindings) {
|
||||
this.relationalValueBindings = Collections.unmodifiableList( relationalValueBindings );
|
||||
for ( RelationalValueBinding relationalValueBinding : getRelationalValueBindings() ) {
|
||||
this.hasDerivedValue = this.hasDerivedValue || relationalValueBinding.isDerived();
|
||||
this.isNullable = this.isNullable && relationalValueBinding.isNullable();
|
||||
}
|
||||
this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -215,9 +215,7 @@ public class CompositeAttributeBinding
|
|||
|
||||
@Override
|
||||
protected RelationalValueBindingContainer getRelationalValueBindingContainer() {
|
||||
final RelationalValueBindingContainer relationalValueBindingContainer = new RelationalValueBindingContainer();
|
||||
collectRelationalValueBindings( relationalValueBindingContainer );
|
||||
return relationalValueBindingContainer;
|
||||
return compositeAttributeBindingContainer.getRelationalValueBindingContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -279,7 +277,6 @@ public class CompositeAttributeBinding
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isIncludedInInsert() {
|
||||
// if the attribute is synthetic, this attribute binding (as a whole) is not insertable;
|
||||
|
@ -316,11 +313,7 @@ public class CompositeAttributeBinding
|
|||
|
||||
@Override
|
||||
protected void collectRelationalValueBindings(RelationalValueBindingContainer relationalValueBindingContainer) {
|
||||
for ( AttributeBinding subAttributeBinding : attributeBindings() ) {
|
||||
if ( AbstractSingularAttributeBinding.class.isInstance( subAttributeBinding ) ) {
|
||||
( (AbstractSingularAttributeBinding) subAttributeBinding ).collectRelationalValueBindings( relationalValueBindingContainer );
|
||||
}
|
||||
}
|
||||
compositeAttributeBindingContainer.collectRelationalValueBindings( relationalValueBindingContainer );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,9 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.spi.binding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
|
@ -51,6 +49,11 @@ public class CompositePluralAttributeElementBinding
|
|||
super( binding );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RelationalValueBindingContainer getRelationalValueContainer() {
|
||||
return compositeAttributeBindingContainer.getRelationalValueBindingContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return Nature.AGGREGATE;
|
||||
|
@ -94,13 +97,6 @@ public class CompositePluralAttributeElementBinding
|
|||
return compositeAttributeBindingContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RelationalValueBinding> getRelationalValueBindings() {
|
||||
final RelationalValueBindingContainer bindingContainer = new RelationalValueBindingContainer();
|
||||
compositeAttributeBindingContainer.collectRelationalValueBindings( bindingContainer );
|
||||
return bindingContainer.relationalValueBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CascadeStyle getCascadeStyle() {
|
||||
return cascadeStyle;
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.spi.binding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -91,8 +90,6 @@ public class CompositePluralAttributeIndexBinding extends AbstractPluralAttribut
|
|||
|
||||
@Override
|
||||
public List<RelationalValueBinding> getRelationalValueBindings() {
|
||||
final RelationalValueBindingContainer bindingContainer = new RelationalValueBindingContainer();
|
||||
compositeAttributeBindingContainer.collectRelationalValueBindings( bindingContainer );
|
||||
return bindingContainer.relationalValueBindings();
|
||||
return compositeAttributeBindingContainer.getRelationalValueBindingContainer().relationalValueBindings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,13 +36,14 @@ public class ManyToAnyPluralAttributeElementBinding extends AbstractPluralAttrib
|
|||
super( binding );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RelationalValueBindingContainer getRelationalValueContainer() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return Nature.MANY_TO_ANY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RelationalValueBinding> getRelationalValueBindings() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,11 +24,9 @@
|
|||
package org.hibernate.metamodel.spi.binding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.internal.FilterConfiguration;
|
||||
import org.hibernate.metamodel.spi.relational.Value;
|
||||
|
||||
/**
|
||||
* Describes plural attributes of {@link org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding.Nature#MANY_TO_MANY} elements
|
||||
|
@ -41,24 +39,24 @@ public class ManyToManyPluralAttributeElementBinding extends AbstractPluralAttri
|
|||
private String manyToManyWhere;
|
||||
private String manyToManyOrderBy;
|
||||
// TODO: really should have value defined (which defines table), but may not know
|
||||
List<RelationalValueBinding> relationalValueBindings;
|
||||
private RelationalValueBindingContainer relationalValueBindingContainer;
|
||||
|
||||
ManyToManyPluralAttributeElementBinding(AbstractPluralAttributeBinding binding) {
|
||||
super( binding );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RelationalValueBindingContainer getRelationalValueContainer() {
|
||||
return relationalValueBindingContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return Nature.MANY_TO_MANY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RelationalValueBinding> getRelationalValueBindings() {
|
||||
return relationalValueBindings;
|
||||
}
|
||||
|
||||
public void setRelationalValueBindings(List<RelationalValueBinding> relationalValueBindings) {
|
||||
this.relationalValueBindings = relationalValueBindings;
|
||||
this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings );
|
||||
}
|
||||
|
||||
public String getManyToManyWhere() {
|
||||
|
|
|
@ -33,23 +33,25 @@ import java.util.List;
|
|||
*/
|
||||
public class OneToManyPluralAttributeElementBinding extends AbstractPluralAttributeAssociationElementBinding {
|
||||
private EntityIdentifier elementEntityIdentifier;
|
||||
private RelationalValueBindingContainer relationalValueBindingContainer;
|
||||
|
||||
OneToManyPluralAttributeElementBinding(AbstractPluralAttributeBinding binding) {
|
||||
super( binding );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RelationalValueBindingContainer getRelationalValueContainer() {
|
||||
return relationalValueBindingContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return Nature.ONE_TO_MANY;
|
||||
}
|
||||
|
||||
public void setElementEntityIdentifier(EntityIdentifier elementEntityIdentifier) {
|
||||
this.elementEntityIdentifier = elementEntityIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RelationalValueBinding> getRelationalValueBindings() {
|
||||
// TODO: ugh, can't call this until after the EntityIdentifier is completely bound...
|
||||
return elementEntityIdentifier.getAttributeBinding().getRelationalValueBindings();
|
||||
this.relationalValueBindingContainer = new RelationalValueBindingContainer(
|
||||
elementEntityIdentifier.getAttributeBinding().getRelationalValueBindings()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,12 @@ public interface PluralAttributeElementBinding {
|
|||
*/
|
||||
public List<RelationalValueBinding> getRelationalValueBindings();
|
||||
|
||||
public boolean isNullable();
|
||||
|
||||
public boolean hasDerivedValue();
|
||||
|
||||
public boolean hasNonNullableValue();
|
||||
|
||||
/**
|
||||
* Retrieves an enumeration describing the mapping nature of the collection's elements.
|
||||
*
|
||||
|
|
|
@ -23,9 +23,10 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.spi.binding;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.metamodel.spi.relational.Column;
|
||||
import org.hibernate.metamodel.spi.relational.ForeignKey;
|
||||
import org.hibernate.cfg.NotYetImplementedException;
|
||||
import org.hibernate.metamodel.spi.relational.TableSpecification;
|
||||
|
||||
/**
|
||||
|
@ -36,10 +37,9 @@ import org.hibernate.metamodel.spi.relational.TableSpecification;
|
|||
public class PluralAttributeKeyBinding {
|
||||
private final AbstractPluralAttributeBinding pluralAttributeBinding;
|
||||
private final SingularAttributeBinding referencedAttributeBinding;
|
||||
private ForeignKey foreignKey;
|
||||
private RelationalValueBindingContainer relationalValueBindingContainer;
|
||||
private boolean isCascadeDeleteEnabled;
|
||||
private boolean inverse;
|
||||
private boolean insertable;
|
||||
private boolean updatable;
|
||||
|
||||
// this knowledge can be implicitly resolved based on the typing information on the referenced owner attribute
|
||||
private HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor();
|
||||
|
@ -69,17 +69,9 @@ public class PluralAttributeKeyBinding {
|
|||
return referencedAttributeBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* The foreign key that defines the scope of this relationship.
|
||||
*
|
||||
* @return The foreign key being bound to.
|
||||
*/
|
||||
public ForeignKey getForeignKey() {
|
||||
return foreignKey;
|
||||
}
|
||||
|
||||
public TableSpecification getCollectionTable() {
|
||||
return foreignKey.getSourceTable();
|
||||
// TODO: get table directly from relationalValueBindingContainer
|
||||
return relationalValueBindingContainer.relationalValueBindings().get( 0 ).getValue().getTable();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,48 +97,47 @@ public class PluralAttributeKeyBinding {
|
|||
this.hibernateTypeDescriptor = hibernateTypeDescriptor;
|
||||
}
|
||||
|
||||
public void setForeignKey(ForeignKey foreignKey) {
|
||||
if ( foreignKey == null ) {
|
||||
throw new AssertionFailure( "foreignKey argument must be non-null." );
|
||||
public List<RelationalValueBinding> getRelationalValueBindings() {
|
||||
return relationalValueBindingContainer.relationalValueBindings();
|
||||
}
|
||||
if ( this.foreignKey != null ) {
|
||||
throw new AssertionFailure( "Foreign key already initialized" );
|
||||
|
||||
public void setRelationalValueBindings(List<RelationalValueBinding> relationalValueBindings) {
|
||||
if ( relationalValueBindings == null || relationalValueBindings.isEmpty() ) {
|
||||
throw new AssertionFailure( "relationalValueBindings argument must be non-null and non-empty." );
|
||||
}
|
||||
this.foreignKey = foreignKey;
|
||||
if ( this.relationalValueBindingContainer != null ) {
|
||||
throw new AssertionFailure( "Relational value bindings have already initialized" );
|
||||
}
|
||||
this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings );
|
||||
if ( this.relationalValueBindingContainer.hasDerivedValue() ) {
|
||||
throw new NotYetImplementedException(
|
||||
"Derived values are not supported when creating a foreign key that targets columns."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCascadeDeleteEnabled() {
|
||||
return isCascadeDeleteEnabled;
|
||||
}
|
||||
|
||||
public void setCascadeDeleteEnabled(boolean isCascadeDeleteEnabled) {
|
||||
this.isCascadeDeleteEnabled = isCascadeDeleteEnabled;
|
||||
}
|
||||
|
||||
public boolean isNullable() {
|
||||
if ( foreignKey == null || foreignKey.getSourceColumns().isEmpty() ) {
|
||||
throw new IllegalStateException( "Foreign key has no columns." );
|
||||
}
|
||||
// cannot be nullable if the foreign key source columns are included in the primary key .
|
||||
if ( foreignKey.getTable().getPrimaryKey().getColumns().containsAll( foreignKey.getSourceColumns() ) ) {
|
||||
// cannot be nullable if the foreign key source columns are included in the primary key
|
||||
// TODO: move this into RelationalValueBindingContainer.
|
||||
if ( getCollectionTable().getPrimaryKey().getColumns().containsAll( relationalValueBindingContainer.columns() ) ) {
|
||||
return false;
|
||||
}
|
||||
for ( Column column : foreignKey.getSourceColumns() ) {
|
||||
if ( column.isNullable() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setInsertable( boolean insertable ){
|
||||
this.insertable = insertable;
|
||||
return relationalValueBindingContainer.hasNullableRelationalValueBinding();
|
||||
}
|
||||
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
public void setUpdatable( boolean updatable ){
|
||||
// The key is updatable if the foreign key *source* columns are updatable;
|
||||
// We don't have the RelationalValueBindings for the FK source columns stored in ForeignKey
|
||||
// so it needs to be set explicitly.
|
||||
this.updatable = updatable;
|
||||
return relationalValueBindingContainer.hasInsertableRelationalValueBinding();
|
||||
}
|
||||
|
||||
public boolean isUpdatable() {
|
||||
return updatable;
|
||||
return relationalValueBindingContainer.hasUpdateableRelationalValueBinding();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ public class RelationalValueBindingContainer {
|
|||
this.isListModifiable = false;
|
||||
}
|
||||
|
||||
|
||||
public RelationalValueBindingContainer() {
|
||||
this.relationalValueBindings = new ArrayList<RelationalValueBinding>();
|
||||
this.isListModifiable = true;
|
||||
|
@ -81,11 +80,12 @@ public class RelationalValueBindingContainer {
|
|||
}
|
||||
|
||||
public boolean hasDerivedValue() {
|
||||
boolean hasDerivedValue = false;
|
||||
for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) {
|
||||
hasDerivedValue = hasDerivedValue || relationalValueBinding.isDerived();
|
||||
if (relationalValueBinding.isDerived() ) {
|
||||
return true;
|
||||
}
|
||||
return hasDerivedValue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasNullableRelationalValueBinding() {
|
||||
|
@ -123,35 +123,4 @@ public class RelationalValueBindingContainer {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
protected static boolean hasNullableRelationalValueBinding(List<RelationalValueBinding> relationalValueBindings) {
|
||||
for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) {
|
||||
if ( relationalValueBinding.isNullable() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static boolean hasInsertableRelationalValueBinding(List<RelationalValueBinding> relationalValueBindings) {
|
||||
for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) {
|
||||
if ( relationalValueBinding.isIncludeInInsert() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static boolean hasUpdateableRelationalValueBinding(List<RelationalValueBinding> relationalValueBindings) {
|
||||
for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) {
|
||||
if ( relationalValueBinding.isIncludeInUpdate() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
}
|
|
@ -746,11 +746,12 @@ public abstract class AbstractCollectionPersister
|
|||
PluralAttributeKeyBinding keyBinding = collection.getPluralAttributeKeyBinding();
|
||||
keyType = keyBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
|
||||
|
||||
int keySpan = keyBinding.getForeignKey().getColumnSpan();
|
||||
int keySpan = keyBinding.getRelationalValueBindings().size();
|
||||
keyColumnNames = new String[keySpan];
|
||||
keyColumnAliases = new String[keySpan];
|
||||
int k = 0;
|
||||
for ( Column keyColumn : keyBinding.getForeignKey().getSourceColumns() ) {
|
||||
for ( RelationalValueBinding keyRelationalValueBinding : keyBinding.getRelationalValueBindings() ) {
|
||||
Column keyColumn = (Column) keyRelationalValueBinding.getValue();
|
||||
// NativeSQL: collect key column and auto-aliases
|
||||
keyColumnNames[k] = keyColumn.getColumnName().getText( dialect );
|
||||
// TODO: does the owner root table need to be in alias?
|
||||
|
|
|
@ -110,8 +110,7 @@ public class OneToManyPersister extends AbstractCollectionPersister {
|
|||
);
|
||||
}
|
||||
final PluralAttributeKeyBinding keyBinding = collection.getPluralAttributeKeyBinding();
|
||||
cascadeDeleteEnabled = keyBinding.getForeignKey().getDeleteRule() == ForeignKey.ReferentialAction.CASCADE &&
|
||||
factory.getDialect().supportsCascadeDelete();;
|
||||
cascadeDeleteEnabled = keyBinding.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete();
|
||||
keyIsNullable = keyBinding.isNullable();
|
||||
keyIsUpdateable = keyBinding.isUpdatable();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.metamodel.spi.binding.basiccollections;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.After;
|
||||
|
@ -45,6 +46,7 @@ import org.hibernate.metamodel.spi.binding.PluralAttributeKeyBinding;
|
|||
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
|
||||
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
|
||||
import org.hibernate.metamodel.spi.domain.PluralAttribute;
|
||||
import org.hibernate.metamodel.spi.relational.Column;
|
||||
import org.hibernate.metamodel.spi.relational.ForeignKey;
|
||||
import org.hibernate.metamodel.spi.relational.Identifier;
|
||||
import org.hibernate.metamodel.spi.relational.TableSpecification;
|
||||
|
@ -174,24 +176,19 @@ public abstract class AbstractBasicCollectionBindingTests extends BaseUnitTestCa
|
|||
assertEquals( expectedFetchTiming, collectionBinding.getFetchTiming() );
|
||||
assertEquals( expectedFetchTiming != FetchTiming.IMMEDIATE, collectionBinding.isLazy() );
|
||||
|
||||
ForeignKey fk = keyBinding.getForeignKey();
|
||||
assertNotNull( fk );
|
||||
assertSame( collectionTable, fk.getSourceTable() );
|
||||
assertEquals( 1, fk.getColumnSpan() );
|
||||
List<RelationalValueBinding> keyRelationalValueBindings = keyBinding.getRelationalValueBindings();
|
||||
assertNotNull( keyRelationalValueBindings );
|
||||
for( RelationalValueBinding keyRelationalValueBinding : keyRelationalValueBindings ) {
|
||||
assertSame( collectionTable, keyRelationalValueBinding.getValue().getTable() );
|
||||
}
|
||||
assertEquals( 1, keyRelationalValueBindings.size() );
|
||||
assertEquals( 1, expectedKeyTargetAttributeBinding.getRelationalValueBindings().size() );
|
||||
Value expectedFKTargetValue = expectedKeyTargetAttributeBinding.getRelationalValueBindings().get( 0 ).getValue();
|
||||
assertEquals( fk.getColumns(), fk.getSourceColumns() );
|
||||
assertEquals( 1, fk.getSourceColumns().size() );
|
||||
assertEquals( 1, fk.getTargetColumns().size() );
|
||||
assertEquals( expectedKeySourceColumnName, fk.getSourceColumns().get( 0 ).getColumnName() );
|
||||
assertSame( expectedFKTargetValue, fk.getTargetColumns().get( 0 ) );
|
||||
assertSame( collectionOwnerBinding.getPrimaryTable(), fk.getTargetTable() );
|
||||
assertEquals( expectedFKTargetValue.getJdbcDataType(), fk.getSourceColumns().get( 0 ).getJdbcDataType() );
|
||||
assertFalse( keyRelationalValueBindings.get( 0 ).isDerived() );
|
||||
assertEquals( expectedKeySourceColumnName, ( (Column) keyRelationalValueBindings.get( 0 ).getValue() ).getColumnName() );
|
||||
assertEquals( expectedFKTargetValue.getJdbcDataType(), keyRelationalValueBindings.get( 0 ).getValue().getJdbcDataType() );
|
||||
|
||||
assertSame( ForeignKey.ReferentialAction.NO_ACTION, fk.getDeleteRule() );
|
||||
assertSame( ForeignKey.ReferentialAction.NO_ACTION, fk.getUpdateRule() );
|
||||
// FK name is null because no default FK name is generated until HHH-7092 is fixed
|
||||
assertNull( fk.getName() );
|
||||
assertFalse( keyBinding.isCascadeDeleteEnabled() );
|
||||
checkEquals(
|
||||
expectedKeyTargetAttributeBinding.getHibernateTypeDescriptor(),
|
||||
keyBinding.getHibernateTypeDescriptor()
|
||||
|
@ -222,7 +219,7 @@ public abstract class AbstractBasicCollectionBindingTests extends BaseUnitTestCa
|
|||
}
|
||||
else {
|
||||
assertEquals( 2, collectionTable.getPrimaryKey().getColumnSpan() );
|
||||
assertSame( fk.getSourceColumns().get( 0 ), collectionTable.getPrimaryKey().getColumns().get( 0 ) );
|
||||
assertSame( keyRelationalValueBindings.get( 0 ).getValue(), collectionTable.getPrimaryKey().getColumns().get( 0 ) );
|
||||
assertSame( elementRelationalValueBinding.getValue(), collectionTable.getPrimaryKey().getColumns().get( 1 ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor;
|
|||
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
|
||||
import org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding;
|
||||
import org.hibernate.metamodel.spi.binding.PluralAttributeKeyBinding;
|
||||
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
|
||||
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
|
||||
import org.hibernate.metamodel.spi.relational.Column;
|
||||
import org.hibernate.metamodel.spi.relational.ForeignKey;
|
||||
|
@ -202,18 +203,12 @@ public abstract class AbstractUnidirectionalOneToManyBindingTests extends BaseUn
|
|||
expectedCollectionTypeClass.cast( collectionHibernateTypeDescriptor.getResolvedTypeMapping() ).getRole()
|
||||
);
|
||||
|
||||
ForeignKey fk = keyBinding.getForeignKey();
|
||||
assertNotNull( fk );
|
||||
assertSame( ForeignKey.ReferentialAction.NO_ACTION, fk.getDeleteRule() );
|
||||
assertSame( ForeignKey.ReferentialAction.NO_ACTION, fk.getUpdateRule() );
|
||||
// FK name is null because no default FK name is generated until HHH-7092 is fixed
|
||||
assertNull( fk.getName() );
|
||||
List<RelationalValueBinding> keyRelationalValueBinding = keyBinding.getRelationalValueBindings();
|
||||
assertNotNull( keyRelationalValueBinding );
|
||||
assertFalse( keyBinding.isCascadeDeleteEnabled() );
|
||||
|
||||
assertSame( expectedElementEntityBinding.getPrimaryTable(), fk.getSourceTable() );
|
||||
assertEquals( 1, fk.getColumnSpan() );
|
||||
assertEquals( fk.getColumns(), fk.getSourceColumns() );
|
||||
assertEquals( 1, fk.getSourceColumns().size() );
|
||||
assertEquals( 1, fk.getTargetColumns().size() );
|
||||
assertSame( expectedElementEntityBinding.getPrimaryTable(), keyBinding.getCollectionTable() );
|
||||
assertEquals( 1, keyRelationalValueBinding.size() );
|
||||
|
||||
SingularAttributeBinding keySourceAttributeBinding =
|
||||
( SingularAttributeBinding ) expectedElementEntityBinding.locateAttributeBinding(
|
||||
|
@ -229,19 +224,12 @@ public abstract class AbstractUnidirectionalOneToManyBindingTests extends BaseUn
|
|||
assertTrue( keySourceValue instanceof Column );
|
||||
Column keySourceColumn = ( Column ) keySourceValue;
|
||||
assertEquals( expectedKeySourceColumnName, keySourceColumn.getColumnName() );
|
||||
assertSame( keySourceColumn, fk.getColumns().get( 0 ) );
|
||||
assertSame( keySourceColumn, fk.getSourceColumns().get( 0 ) );
|
||||
}
|
||||
|
||||
assertSame( collectionOwnerBinding.getPrimaryTable(), fk.getTargetTable() );
|
||||
assertEquals( 1, expectedKeyTargetAttributeBinding.getRelationalValueBindings().size() );
|
||||
assertSame(
|
||||
expectedKeyTargetAttributeBinding.getRelationalValueBindings().get( 0 ).getValue(),
|
||||
fk.getTargetColumns().get( 0 )
|
||||
);
|
||||
assertEquals(
|
||||
expectedKeyTargetAttributeBinding.getRelationalValueBindings().get( 0 ).getValue().getJdbcDataType(),
|
||||
fk.getColumns().get( 0 ).getJdbcDataType()
|
||||
keyRelationalValueBinding.get( 0 ).getValue().getJdbcDataType()
|
||||
);
|
||||
|
||||
checkEquals(
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
@FailureExpectedWithNewMetamodel
|
||||
public class UnidirCollectionWithMultipleOwnerTest extends BaseCoreFunctionalTestCase {
|
||||
@Test
|
||||
public void testUnidirCollectionWithMultipleOwner() throws Exception {
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.junit.Test;
|
|||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.collection.internal.PersistentMap;
|
||||
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
|
Loading…
Reference in New Issue