HHH-18470: fix duplicate generated FK names for TABLE_PER_CLASS inheritance

This commit is contained in:
Paria 2024-09-08 14:12:14 +02:00 committed by GitHub
parent ee00217733
commit f5e1d1cd73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 110 additions and 2 deletions

View File

@ -8,7 +8,6 @@ package org.hibernate.mapping;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Internal;
@ -70,10 +69,12 @@ public class DenormalizedTable extends Table {
if ( foreignKey.getReferencedTable() == null ) {
foreignKey.setReferencedTable( referencedClass.getTable() );
}
final ForeignKey denormalizedForeignKey = createDenormalizedForeignKey( foreignKey );
createForeignKey(
context.getBuildingOptions()
.getImplicitNamingStrategy()
.determineForeignKeyName( new ForeignKeyNameSource( foreignKey, this, context ) )
.determineForeignKeyName( new ForeignKeyNameSource( denormalizedForeignKey, this, context ) )
.render( context.getMetadataCollector().getDatabase().getDialect() ),
foreignKey.getColumns(),
foreignKey.getReferencedEntityName(),
@ -83,6 +84,18 @@ public class DenormalizedTable extends Table {
}
}
private ForeignKey createDenormalizedForeignKey(ForeignKey includedTableFk) {
final ForeignKey denormalizedForeignKey = new ForeignKey(this);
denormalizedForeignKey.setReferencedEntityName( includedTableFk.getReferencedEntityName() );
denormalizedForeignKey.setKeyDefinition( includedTableFk.getKeyDefinition() );
denormalizedForeignKey.setReferencedTable( includedTableFk.getReferencedTable() );
denormalizedForeignKey.addReferencedColumns( includedTableFk.getReferencedColumns() );
for ( Column keyColumn : includedTableFk.getColumns() ) {
denormalizedForeignKey.addColumn( keyColumn );
}
return denormalizedForeignKey;
}
@Override
public Column getColumn(Column column) {
Column superColumn = super.getColumn( column );

View File

@ -0,0 +1,95 @@
package org.hibernate.orm.test.inheritance;
import jakarta.persistence.*;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.junit.jupiter.api.Test;
import java.io.Serializable;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Paria Hosseiny
*/
@JiraKey("HHH-18470")
@Jpa(
annotatedClasses = {
DenormalizedTableForeignKeyGeneratorTest.Employee.class,
DenormalizedTableForeignKeyGeneratorTest.Manager.class,
DenormalizedTableForeignKeyGeneratorTest.Address.class,
DenormalizedTableForeignKeyGeneratorTest.Territory.class
}
)
@RequiresDialect(H2Dialect.class)
public class DenormalizedTableForeignKeyGeneratorTest {
@Test
public void shouldCreateForeignKeyForSubclasses(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
String managerQuery = "select CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS " +
"WHERE TABLE_NAME='MANAGER' " +
"AND CONSTRAINT_TYPE='FOREIGN KEY'";
List<String> managerForeignKeyNames = entityManager.createNativeQuery(managerQuery).getResultList();
String employeeQuery = "select CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS " +
"WHERE TABLE_NAME='EMPLOYEE' " +
"AND CONSTRAINT_TYPE='FOREIGN KEY'";
String employeeForeignKeyName = entityManager.createNativeQuery(employeeQuery).getSingleResult().toString();
assertThat(employeeForeignKeyName).isNotNull();
assertThat(managerForeignKeyNames).isNotNull().hasSize(2);
assertThat(managerForeignKeyNames).doesNotContain(employeeForeignKeyName);
}
);
}
@Entity(name = "Employee")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
static class Employee implements Serializable {
@Id
@GeneratedValue
Long id;
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
private Address address;
}
@Entity(name = "Manager")
static class Manager extends Employee {
@OneToOne(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.ALL)
private Territory territory;
}
@Entity(name = "Address")
static class Address {
@Id
@GeneratedValue
Long id;
@Column(nullable = false, columnDefinition = "TEXT")
private String address = "";
}
@Entity(name = "Territory")
static class Territory {
@Id
@GeneratedValue
Long id;
@Column
private String location = "";
}
}