| When using a custom PhysicalNamingStrategy the `columnNames` require the physical name for JoinColumn (ManyToOne), but the logical name for normal columns. (imo the logical name is expected?) I have tried to create a runnable example here: https://github.com/hpoul/hibernate-joincolumns-test-case/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java Models:
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"col1_id", "col2"}))
@Entity
static class Test2 {
@Id
public Long id;
@JoinColumn(nullable = false)
@ManyToOne
public Test1 col1;
public String col2;
}
Setup
Properties props = new Properties();
props.put(AvailableSettings.HBM2DDL_AUTO, "create");
props.put(AvailableSettings.PHYSICAL_NAMING_STRATEGY, TestPhysicalNamingStrategy.class.getName());
Persistence.generateSchema("templatePU", props);
`TestPhysicalNamingStrategy` is a simple PhysicalNamingStrategy which simply appends _PHYSICAL to all names:
return new Identifier(name.getText() + "_PHYSICAL", false);
Problem when running with:
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"col1_id", "col2"}))
The error is:
Caused by: org.hibernate.AnnotationException: Unable to create unique key constraint (col1_id, col2) on table JPAUnitTestCase$Test2_PHYSICAL: database column 'col1_id' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.buildUniqueKeyFromColumnNames(InFlightMetadataCollectorImpl.java:2074)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.buildUniqueKeyFromColumnNames(InFlightMetadataCollectorImpl.java:1935)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processUniqueConstraintHolders(InFlightMetadataCollectorImpl.java:1923)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1595)
but with the following code it works:
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"col1_id_PHYSICAL", "col2"}))
which is weird, because i'd expect both being _PHYSICAL or both being logical names. my 2 cents I have traced the problem back to: Ejb3JoinColumn#buildDefaultColumnName(final PersistentClass referencedEntity, final String logicalReferencedColumn) - this method returns the physical name:
return physicalNamingStrategy.toPhysicalColumnName( columnIdentifier, database.getJdbcEnvironment() )
.render( database.getJdbcEnvironment().getDialect() );
but it is called by Ejb3JoinColumn#linkValueUsingDefaultColumnNaming which stores the result as logical name:
String columnName = buildDefaultColumnName( referencedEntity, logicalReferencedColumn );
setLogicalColumnName( columnName );
( https://github.com/hibernate/hibernate-orm/blob/5.2/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java#L468-L471 ) which probably makes no real sense? anyway, this makes the InFlightMetadataCollectorImpl -> columnNameBindingByTableMap.get("Test2").logicalToPhysical map look like:
binding = {InFlightMetadataCollectorImpl$TableColumnNameBinding@3020}
tableName = "JPAUnitTestCase$Test2_PHYSICAL"
logicalToPhysical = {HashMap@3021} size = 3
0 = {HashMap$Node@3032} "col1_id_PHYSICAL" -> "col1_id_PHYSICAL"
1 = {HashMap$Node@3033} "id" -> "id_PHYSICAL"
2 = {HashMap$Node@3034} "col2" -> "col2_PHYSICAL"
physicalToLogical = {HashMap@3029} size = 3
0 = {HashMap$Node@3045} "col2_PHYSICAL" -> "col2"
1 = {HashMap$Node@3046} "id_PHYSICAL" -> "id"
2 = {HashMap$Node@3047} "col1_id_PHYSICAL" -> "col1_id_PHYSICAL"
which makes no sense for the JoinColumn.. |