HHH-16918 Unify column duplication checking logic under Value
This commit is contained in:
parent
bafc2ae88e
commit
d3b6eaea53
|
@ -392,46 +392,18 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
checkColumnDuplication();
|
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 {
|
private void checkColumnDuplication() throws MappingException {
|
||||||
|
final String owner = "collection '" + getReferencedPropertyName() + "'";
|
||||||
final HashSet<String> cols = new HashSet<>();
|
final HashSet<String> cols = new HashSet<>();
|
||||||
checkColumnDuplication( cols, getKey() );
|
getKey().checkColumnDuplication( cols, owner );
|
||||||
if ( isIndexed() ) {
|
if ( isIndexed() ) {
|
||||||
checkColumnDuplication(
|
( (IndexedCollection) this ).getIndex().checkColumnDuplication( cols, owner );
|
||||||
cols,
|
|
||||||
( (IndexedCollection) this ).getIndex()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if ( isIdentified() ) {
|
if ( isIdentified() ) {
|
||||||
checkColumnDuplication(
|
( (IdentifierCollection) this ).getIdentifier().checkColumnDuplication( cols, owner );
|
||||||
cols,
|
|
||||||
( (IdentifierCollection) this ).getIdentifier()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if ( !isOneToMany() ) {
|
if ( !isOneToMany() ) {
|
||||||
checkColumnDuplication( cols, getElement() );
|
getElement().checkColumnDuplication( cols, owner );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ import org.hibernate.usertype.CompositeUserType;
|
||||||
|
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
import static org.hibernate.generator.EventType.INSERT;
|
import static org.hibernate.generator.EventType.INSERT;
|
||||||
|
import static org.hibernate.mapping.MappingHelper.checkPropertyColumnDuplication;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapping model object that represents an {@linkplain jakarta.persistence.Embeddable embeddable class}.
|
* A mapping model object that represents an {@linkplain jakarta.persistence.Embeddable embeddable class}.
|
||||||
|
@ -283,47 +284,14 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
||||||
this.structName = structName;
|
this.structName = structName;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkColumnDuplication() throws MappingException {
|
@Override
|
||||||
checkPropertyColumnDuplication( new HashSet<>(), getProperties() );
|
public void checkColumnDuplication(Set<String> distinctColumns, String owner) {
|
||||||
}
|
if ( aggregateColumn == null ) {
|
||||||
protected void checkColumnDuplication(java.util.Set<String> distinctColumns, Value value)
|
checkPropertyColumnDuplication( distinctColumns, getProperties(), owner );
|
||||||
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)"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
checkPropertyColumnDuplication( new HashSet<>(), getProperties(), "component '" + getRoleName() + "'" );
|
||||||
protected void checkPropertyColumnDuplication(Set<String> distinctColumns, List<Property> properties)
|
aggregateColumn.getValue().checkColumnDuplication( distinctColumns, owner );
|
||||||
throws MappingException {
|
|
||||||
for ( Property prop : properties ) {
|
|
||||||
Value value = prop.getValue();
|
|
||||||
if ( value instanceof Component ) {
|
|
||||||
Component component = (Component) value;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,18 +6,20 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.mapping;
|
package org.hibernate.mapping;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.Internal;
|
import org.hibernate.Internal;
|
||||||
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.BootLogging;
|
import org.hibernate.boot.BootLogging;
|
||||||
import org.hibernate.boot.model.internal.DelayedParameterizedTypeBean;
|
import org.hibernate.boot.model.internal.DelayedParameterizedTypeBean;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.boot.spi.MetadataImplementor;
|
import org.hibernate.boot.spi.MetadataImplementor;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
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.internal.FallbackBeanInstanceProducer;
|
||||||
import org.hibernate.resource.beans.spi.ManagedBean;
|
import org.hibernate.resource.beans.spi.ManagedBean;
|
||||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||||
|
@ -237,4 +239,15 @@ public final class MappingHelper {
|
||||||
|
|
||||||
return new ProvidedInstanceManagedBeanImpl<>( userCollectionType );
|
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 java.util.Comparator.comparing;
|
||||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||||
import static org.hibernate.internal.util.StringHelper.root;
|
import static org.hibernate.internal.util.StringHelper.root;
|
||||||
|
import static org.hibernate.mapping.MappingHelper.checkPropertyColumnDuplication;
|
||||||
import static org.hibernate.sql.Template.collectColumnNames;
|
import static org.hibernate.sql.Template.collectColumnNames;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1042,47 +1043,6 @@ public abstract class PersistentClass implements IdentifiableTypeClass, Attribut
|
||||||
this.isAbstract = isAbstract;
|
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")
|
@Deprecated(since = "6.0")
|
||||||
protected Iterator<Property> getNonDuplicatedPropertyIterator() {
|
protected Iterator<Property> getNonDuplicatedPropertyIterator() {
|
||||||
return getUnjoinedPropertyIterator();
|
return getUnjoinedPropertyIterator();
|
||||||
|
@ -1098,20 +1058,21 @@ public abstract class PersistentClass implements IdentifiableTypeClass, Attribut
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkColumnDuplication() {
|
protected void checkColumnDuplication() {
|
||||||
|
final String owner = "entity '" + getEntityName() + "'";
|
||||||
final HashSet<String> cols = new HashSet<>();
|
final HashSet<String> cols = new HashSet<>();
|
||||||
if ( getIdentifierMapper() == null ) {
|
if ( getIdentifierMapper() == null ) {
|
||||||
//an identifier mapper => getKey will be included in the getNonDuplicatedPropertyIterator()
|
//an identifier mapper => getKey will be included in the getNonDuplicatedPropertyIterator()
|
||||||
//and checked later, so it needs to be excluded
|
//and checked later, so it needs to be excluded
|
||||||
checkColumnDuplication( cols, getKey() );
|
getKey().checkColumnDuplication( cols, owner );
|
||||||
}
|
}
|
||||||
if ( isDiscriminatorInsertable() ) {
|
if ( isDiscriminatorInsertable() && getDiscriminator() != null ) {
|
||||||
checkColumnDuplication( cols, getDiscriminator() );
|
getDiscriminator().checkColumnDuplication( cols, owner );
|
||||||
}
|
}
|
||||||
checkPropertyColumnDuplication( cols, getNonDuplicatedProperties() );
|
checkPropertyColumnDuplication( cols, getNonDuplicatedProperties(), owner );
|
||||||
for ( Join join : getJoins() ) {
|
for ( Join join : getJoins() ) {
|
||||||
cols.clear();
|
cols.clear();
|
||||||
checkColumnDuplication( cols, join.getKey() );
|
join.getKey().checkColumnDuplication( cols, owner );
|
||||||
checkPropertyColumnDuplication( cols, join.getProperties() );
|
checkPropertyColumnDuplication( cols, join.getProperties(), owner );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,11 @@ package org.hibernate.mapping;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.FetchMode;
|
import org.hibernate.FetchMode;
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
|
import org.hibernate.Internal;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.engine.spi.Mapping;
|
import org.hibernate.engine.spi.Mapping;
|
||||||
|
@ -179,4 +181,31 @@ public interface Value extends Serializable {
|
||||||
default String getExtraCreateTableInfo() {
|
default String getExtraCreateTableInfo() {
|
||||||
return "";
|
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