HHH-16918 Unify column duplication checking logic under Value
This commit is contained in:
parent
d2a88cb883
commit
173e247812
|
@ -392,46 +392,18 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
checkColumnDuplication();
|
||||
}
|
||||
|
||||
private void checkColumnDuplication(java.util.Set<String> distinctColumns, Value value)
|
||||
throws MappingException {
|
||||
final boolean[] insertability = value.getColumnInsertability();
|
||||
final boolean[] updatability = value.getColumnUpdateability();
|
||||
int i = 0;
|
||||
for ( Selectable selectable : value.getSelectables() ) {
|
||||
// exclude formulas and columns that are not insertable or updatable
|
||||
// since these values can be repeated (HHH-5393)
|
||||
if ( !selectable.isFormula() && ( insertability[i] || updatability[i] ) ) {
|
||||
Column col = (Column) selectable;
|
||||
if ( !distinctColumns.add( col.getName() ) ) {
|
||||
throw new MappingException(
|
||||
"Repeated column in mapping for collection: "
|
||||
+ getRole()
|
||||
+ " column: "
|
||||
+ col.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkColumnDuplication() throws MappingException {
|
||||
final String owner = "collection '" + getReferencedPropertyName() + "'";
|
||||
final HashSet<String> cols = new HashSet<>();
|
||||
checkColumnDuplication( cols, getKey() );
|
||||
getKey().checkColumnDuplication( cols, owner );
|
||||
if ( isIndexed() ) {
|
||||
checkColumnDuplication(
|
||||
cols,
|
||||
( (IndexedCollection) this ).getIndex()
|
||||
);
|
||||
( (IndexedCollection) this ).getIndex().checkColumnDuplication( cols, owner );
|
||||
}
|
||||
if ( isIdentified() ) {
|
||||
checkColumnDuplication(
|
||||
cols,
|
||||
( (IdentifierCollection) this ).getIdentifier()
|
||||
);
|
||||
( (IdentifierCollection) this ).getIdentifier().checkColumnDuplication( cols, owner );
|
||||
}
|
||||
if ( !isOneToMany() ) {
|
||||
checkColumnDuplication( cols, getElement() );
|
||||
getElement().checkColumnDuplication( cols, owner );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.hibernate.type.Type;
|
|||
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import static org.hibernate.id.IdentifierGeneratorHelper.POST_INSERT_INDICATOR;
|
||||
import static org.hibernate.mapping.MappingHelper.checkPropertyColumnDuplication;
|
||||
|
||||
/**
|
||||
* A mapping model object that represents an {@linkplain jakarta.persistence.Embeddable embeddable class}.
|
||||
|
@ -279,47 +280,14 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
|||
this.structName = structName;
|
||||
}
|
||||
|
||||
protected void checkColumnDuplication() throws MappingException {
|
||||
checkPropertyColumnDuplication( new HashSet<>(), getProperties() );
|
||||
}
|
||||
protected void checkColumnDuplication(java.util.Set<String> distinctColumns, Value value)
|
||||
throws MappingException {
|
||||
if ( value != null ) {
|
||||
for ( Selectable columnOrFormula : value.getSelectables() ) {
|
||||
if ( !columnOrFormula.isFormula() ) {
|
||||
final Column col = (Column) columnOrFormula;
|
||||
if ( !distinctColumns.add( col.getName() ) ) {
|
||||
throw new MappingException(
|
||||
"Column '" + col.getName()
|
||||
+ "' is duplicated in mapping for component '" + getRoleName()
|
||||
+ "' (use '@Column(insertable=false, updatable=false)' when mapping multiple properties to the same column)"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkPropertyColumnDuplication(Set<String> distinctColumns, List<Property> properties)
|
||||
throws MappingException {
|
||||
for ( Property prop : properties ) {
|
||||
Value value = prop.getValue();
|
||||
if ( value instanceof Component ) {
|
||||
Component component = (Component) value;
|
||||
AggregateColumn aggregateColumn = component.getAggregateColumn();
|
||||
@Override
|
||||
public void checkColumnDuplication(Set<String> distinctColumns, String owner) {
|
||||
if ( aggregateColumn == null ) {
|
||||
checkPropertyColumnDuplication( distinctColumns, component.getProperties() );
|
||||
checkPropertyColumnDuplication( distinctColumns, getProperties(), owner );
|
||||
}
|
||||
else {
|
||||
component.checkColumnDuplication();
|
||||
checkColumnDuplication( distinctColumns, aggregateColumn.getValue() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( prop.isUpdateable() || prop.isInsertable() ) {
|
||||
checkColumnDuplication( distinctColumns, value);
|
||||
}
|
||||
}
|
||||
checkPropertyColumnDuplication( new HashSet<>(), getProperties(), "component '" + getRoleName() + "'" );
|
||||
aggregateColumn.getValue().checkColumnDuplication( distinctColumns, owner );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,18 +6,20 @@
|
|||
*/
|
||||
package org.hibernate.mapping;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.BootLogging;
|
||||
import org.hibernate.boot.model.internal.DelayedParameterizedTypeBean;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.mapping.MappingModelCreationLogging;
|
||||
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
|
||||
import org.hibernate.resource.beans.spi.ManagedBean;
|
||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||
|
@ -237,4 +239,15 @@ public final class MappingHelper {
|
|||
|
||||
return new ProvidedInstanceManagedBeanImpl<>( userCollectionType );
|
||||
}
|
||||
|
||||
public static void checkPropertyColumnDuplication(
|
||||
Set<String> distinctColumns,
|
||||
List<Property> properties,
|
||||
String owner) throws MappingException {
|
||||
for ( Property prop : properties ) {
|
||||
if ( prop.isUpdateable() || prop.isInsertable() ) {
|
||||
prop.getValue().checkColumnDuplication( distinctColumns, owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import static java.util.Collections.unmodifiableList;
|
|||
import static java.util.Comparator.comparing;
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
import static org.hibernate.internal.util.StringHelper.root;
|
||||
import static org.hibernate.mapping.MappingHelper.checkPropertyColumnDuplication;
|
||||
import static org.hibernate.sql.Template.collectColumnNames;
|
||||
|
||||
/**
|
||||
|
@ -1042,47 +1043,6 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
|||
this.isAbstract = isAbstract;
|
||||
}
|
||||
|
||||
protected void checkColumnDuplication(Set<String> distinctColumns, Value value)
|
||||
throws MappingException {
|
||||
if ( value != null ) {
|
||||
for ( Selectable columnOrFormula : value.getSelectables() ) {
|
||||
if ( !columnOrFormula.isFormula() ) {
|
||||
final Column col = (Column) columnOrFormula;
|
||||
if ( !distinctColumns.add( col.getName() ) ) {
|
||||
throw new MappingException(
|
||||
"Column '" + col.getName()
|
||||
+ "' is duplicated in mapping for entity '" + getEntityName()
|
||||
+ "' (use '@Column(insertable=false, updatable=false)' when mapping multiple properties to the same column)"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkPropertyColumnDuplication(Set<String> distinctColumns, List<Property> properties)
|
||||
throws MappingException {
|
||||
for ( Property prop : properties ) {
|
||||
final Value value = prop.getValue();
|
||||
if ( value instanceof Component ) {
|
||||
final Component component = (Component) value;
|
||||
final AggregateColumn aggregateColumn = component.getAggregateColumn();
|
||||
if ( aggregateColumn == null ) {
|
||||
checkPropertyColumnDuplication( distinctColumns, component.getProperties() );
|
||||
}
|
||||
else {
|
||||
component.checkColumnDuplication();
|
||||
checkColumnDuplication( distinctColumns, aggregateColumn.getValue() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( prop.isUpdateable() || prop.isInsertable() ) {
|
||||
checkColumnDuplication( distinctColumns, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(since = "6.0")
|
||||
protected Iterator<Property> getNonDuplicatedPropertyIterator() {
|
||||
return getUnjoinedPropertyIterator();
|
||||
|
@ -1098,20 +1058,21 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
|||
}
|
||||
|
||||
protected void checkColumnDuplication() {
|
||||
final String owner = "entity '" + getEntityName() + "'";
|
||||
final HashSet<String> cols = new HashSet<>();
|
||||
if ( getIdentifierMapper() == null ) {
|
||||
//an identifier mapper => getKey will be included in the getNonDuplicatedPropertyIterator()
|
||||
//and checked later, so it needs to be excluded
|
||||
checkColumnDuplication( cols, getKey() );
|
||||
getKey().checkColumnDuplication( cols, owner );
|
||||
}
|
||||
if ( isDiscriminatorInsertable() ) {
|
||||
checkColumnDuplication( cols, getDiscriminator() );
|
||||
if ( isDiscriminatorInsertable() && getDiscriminator() != null ) {
|
||||
getDiscriminator().checkColumnDuplication( cols, owner );
|
||||
}
|
||||
checkPropertyColumnDuplication( cols, getNonDuplicatedProperties() );
|
||||
checkPropertyColumnDuplication( cols, getNonDuplicatedProperties(), owner );
|
||||
for ( Join join : getJoins() ) {
|
||||
cols.clear();
|
||||
checkColumnDuplication( cols, join.getKey() );
|
||||
checkPropertyColumnDuplication( cols, join.getProperties() );
|
||||
join.getKey().checkColumnDuplication( cols, owner );
|
||||
checkPropertyColumnDuplication( cols, join.getProperties(), owner );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,11 @@ package org.hibernate.mapping;
|
|||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.engine.spi.Mapping;
|
||||
|
@ -174,4 +176,36 @@ public interface Value extends Serializable {
|
|||
boolean isColumnInsertable(int index);
|
||||
|
||||
boolean isColumnUpdateable(int index);
|
||||
|
||||
@Incubating
|
||||
default String getExtraCreateTableInfo() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this value contains any duplicate column. A column
|
||||
* is considered duplicate when its {@link Column#getName() name} is
|
||||
* already contained in the {@code distinctColumn} set.
|
||||
* <p>
|
||||
* If a duplicate column is found, a {@link MappingException} is thrown.
|
||||
*
|
||||
* @param distinctColumns set containing the names of the columns to check
|
||||
* @param owner the owner of this value, used just for error reporting
|
||||
*/
|
||||
@Internal
|
||||
default void checkColumnDuplication(Set<String> distinctColumns, String owner) {
|
||||
for ( int i = 0; i < getSelectables().size(); i++ ) {
|
||||
final Selectable selectable = getSelectables().get( i );
|
||||
if ( isColumnInsertable( i ) || isColumnUpdateable( i ) ) {
|
||||
final Column col = (Column) selectable;
|
||||
if ( !distinctColumns.add( col.getName() ) ) {
|
||||
throw new MappingException(
|
||||
"Column '" + col.getName()
|
||||
+ "' is duplicated in mapping for " + owner
|
||||
+ " (use '@Column(insertable=false, updatable=false)' when mapping multiple properties to the same column)"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue