[HHH-17065] Unique Index on PrimaryKey orders primary key columns.
This commit is contained in:
parent
3a84e408d6
commit
b431029bff
|
@ -211,6 +211,8 @@ The second INSERT statement fails because of the unique constraint violation.
|
|||
|
||||
The {jpaJavadocUrlPrefix}Index.html[`@Index`] annotation is used by the automated schema generation tool to create a database index.
|
||||
|
||||
TIP: Creating unique index containing all primary key columns will result in ordering primary key columns specified by `columnList`
|
||||
|
||||
Considering the following entity mapping. Hibernate generates the index when creating the database schema:
|
||||
|
||||
[[schema-generation-columns-index-mapping-example]]
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.boot.model.relational;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -17,7 +18,9 @@ import org.hibernate.dialect.temptable.TemporaryTableColumn;
|
|||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Constraint;
|
||||
import org.hibernate.mapping.PrimaryKey;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
import org.hibernate.mapping.UserDefinedType;
|
||||
|
||||
import static java.lang.Math.log;
|
||||
|
@ -45,6 +48,15 @@ public class ColumnOrderingStrategyStandard implements ColumnOrderingStrategy {
|
|||
|
||||
@Override
|
||||
public List<Column> orderConstraintColumns(Constraint constraint, Metadata metadata) {
|
||||
// We try to find uniqueKey constraint containing only primary key.
|
||||
// This uniqueKey then orders primaryKey columns. Otherwise, order as usual.
|
||||
if ( constraint instanceof PrimaryKey ) {
|
||||
UniqueKey uniqueKey = ((PrimaryKey) constraint).getOrderingUniqueKey();
|
||||
if ( uniqueKey != null ) {
|
||||
return uniqueKey.getColumns();
|
||||
}
|
||||
}
|
||||
|
||||
return orderColumns( constraint.getColumns(), metadata );
|
||||
}
|
||||
|
||||
|
|
|
@ -424,9 +424,9 @@ public abstract class PersistentClass implements IdentifiableTypeClass, Attribut
|
|||
final Table table = getTable();
|
||||
final PrimaryKey pk = new PrimaryKey( table );
|
||||
pk.setName( PK_ALIAS.toAliasString( table.getName() ) );
|
||||
table.setPrimaryKey( pk );
|
||||
|
||||
pk.addColumns( getKey() );
|
||||
|
||||
table.setPrimaryKey( pk );
|
||||
}
|
||||
|
||||
public abstract String getWhere();
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.jboss.logging.Logger;
|
|||
public class PrimaryKey extends Constraint {
|
||||
private static final Logger log = Logger.getLogger( PrimaryKey.class );
|
||||
|
||||
private UniqueKey orderingUniqueKey = null;
|
||||
private int[] originalOrder;
|
||||
|
||||
public PrimaryKey(Table table){
|
||||
|
@ -117,6 +118,14 @@ public class PrimaryKey extends Constraint {
|
|||
return Arrays.asList( columnsInOriginalOrder );
|
||||
}
|
||||
|
||||
public void setOrderingUniqueKey(UniqueKey uniqueKey) {
|
||||
this.orderingUniqueKey = uniqueKey;
|
||||
}
|
||||
|
||||
public UniqueKey getOrderingUniqueKey() {
|
||||
return this.orderingUniqueKey;
|
||||
}
|
||||
|
||||
@Internal
|
||||
public void reorderColumns(List<Column> reorderedColumns) {
|
||||
if ( originalOrder != null ) {
|
||||
|
@ -126,12 +135,13 @@ public class PrimaryKey extends Constraint {
|
|||
assert getColumns().size() == reorderedColumns.size() && getColumns().containsAll( reorderedColumns );
|
||||
final List<Column> columns = getColumns();
|
||||
originalOrder = new int[columns.size()];
|
||||
for ( int i = 0; i < reorderedColumns.size(); i++ ) {
|
||||
final Column reorderedColumn = reorderedColumns.get( i );
|
||||
List<Column> newColumns = getOrderingUniqueKey() != null ? getOrderingUniqueKey().getColumns() : reorderedColumns;
|
||||
for ( int i = 0; i < newColumns.size(); i++ ) {
|
||||
final Column reorderedColumn = newColumns.get( i );
|
||||
originalOrder[i] = columns.indexOf( reorderedColumn );
|
||||
}
|
||||
columns.clear();
|
||||
columns.addAll( reorderedColumns );
|
||||
columns.addAll( newColumns );
|
||||
}
|
||||
|
||||
@Internal
|
||||
|
|
|
@ -357,10 +357,10 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
|||
// any sharing the same columns as other defined unique keys; this is needed for the annotation
|
||||
// processor since it creates unique constraints automagically for the user
|
||||
// 2) Remove any unique keys that share the same columns as the primary key; again, this is
|
||||
// needed for the annotation processor to handle @Id @OneToOne cases. In such cases the
|
||||
// unique key is unnecessary because a primary key is already unique by definition. We handle
|
||||
// needed for the annotation processor to handle @Id @OneToOne cases. In such cases we handle
|
||||
// this case specifically because some databases fail if you try to apply a unique key to
|
||||
// the primary key columns which causes schema export to fail in these cases.
|
||||
// the primary key columns which causes schema export to fail in these cases. Furthermore, we
|
||||
// pass the unique key to a primary key for reordering columns specified by the unique key.
|
||||
if ( !uniqueKeys.isEmpty() ) {
|
||||
if ( uniqueKeys.size() == 1 ) {
|
||||
// we have to worry about condition 2 above, but not condition 1
|
||||
|
@ -395,6 +395,7 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
|||
|
||||
// condition 2 : check against pk
|
||||
if ( !removeIt && isSameAsPrimaryKeyColumns( uniqueKeyEntry.getValue() ) ) {
|
||||
primaryKey.setOrderingUniqueKey(uniqueKeyEntry.getValue());
|
||||
removeIt = true;
|
||||
}
|
||||
|
||||
|
@ -413,7 +414,7 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
|||
return false;
|
||||
}
|
||||
return primaryKey.getColumns().containsAll( uniqueKey.getColumns() )
|
||||
&& uniqueKey.getColumns().containsAll( primaryKey.getColumns() );
|
||||
&& primaryKey.getColumns().size() == uniqueKey.getColumns().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -471,6 +472,7 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
|||
|
||||
public void setPrimaryKey(PrimaryKey primaryKey) {
|
||||
this.primaryKey = primaryKey;
|
||||
checkPrimaryKeyUniqueKey();
|
||||
}
|
||||
|
||||
public Index getOrCreateIndex(String indexName) {
|
||||
|
@ -580,6 +582,21 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
|||
return foreignKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for uniqueKey containing only whole primary key and sets
|
||||
* order of the columns accordingly
|
||||
*/
|
||||
private void checkPrimaryKeyUniqueKey() {
|
||||
final Iterator<Map.Entry<String,UniqueKey>> uniqueKeyEntries = uniqueKeys.entrySet().iterator();
|
||||
while ( uniqueKeyEntries.hasNext() ) {
|
||||
final Map.Entry<String,UniqueKey> uniqueKeyEntry = uniqueKeyEntries.next();
|
||||
|
||||
if ( isSameAsPrimaryKeyColumns( uniqueKeyEntry.getValue() ) ) {
|
||||
primaryKey.setOrderingUniqueKey(uniqueKeyEntry.getValue());
|
||||
uniqueKeyEntries.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This must be done outside of Table, rather than statically, to ensure
|
||||
// deterministic alias names. See HHH-2448.
|
||||
|
|
|
@ -14,6 +14,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
|
@ -71,6 +73,9 @@ class CompositePrimaryKeyColumnOrderTest {
|
|||
}
|
||||
|
||||
@Entity
|
||||
@Table(
|
||||
indexes = @Index(unique = true, columnList = "b, a")
|
||||
)
|
||||
@IdClass( CompositePrimaryKey.class )
|
||||
static class TestEntity {
|
||||
|
||||
|
|
Loading…
Reference in New Issue