Hello there Hibernate community,
I’ve currently migrated from hibernate version 3.x.x to 5.2.x and seem to be having trouble with the hbm2ddl feature when being set to update when being run against Oracle 11g or 12c, because it is trying to recreate tables that are already existent, and trying to assign foreign key constraints to tables that already have a FK defined.
I found this out from the debug logs :
2018-06-11 09:54:41 DEBUG [org.hibernate.SQL] - <create table TICKET (ID number(10,0) not null, ...>
Which fails with: ORA-00955: name is already used by an existing object (because the table already exists)
Also, I see from the log files that hibernate is trying to create FK’s for objects that already have FKs associated:
2018-06-11 09:54:42 DEBUG [org.hibernate.SQL] - <alter table ACL_PERMISSION add constraint FKf3uxxowxhq1obcesxydy92yuq foreign key (PERMISSIONSUBJECTID) references ACL_PERMISSIONSUBJECTS>
Which fails with: ORA-02275: such a referential constraint already exists in the table
After googling around, I’ve found that this seems to be related to both HHH-12059 and HHH-10574 which suggest that the 5.2.14 version of hibernate should have this working. This did not solve my problem.
I’ve also found a stackoverflow topic (can’t provide link due to new user), which suggests the use of Implicit and Physical naming strategies in order to achieve naming backwards compatibility.
I’'ve created the following physical naming strategy (can’t provide link due to new account):
public class ImprovedNamingStrategy implements PhysicalNamingStrategy {
@Override
public Identifier toPhysicalCatalogName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
@Override
public Identifier toPhysicalColumnName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
@Override
public Identifier toPhysicalSchemaName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
@Override
public Identifier toPhysicalSequenceName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
@Override
public Identifier toPhysicalTableName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
private Identifier convert(Identifier identifier) {
if (identifier == null || StringUtils.isBlank(identifier.getText())) {
return identifier;
}
String regex = "([a-z])([A-Z])";
String replacement = "$1_$2";
String newName = identifier.getText().replaceAll(regex, replacement).toLowerCase();
return Identifier.toIdentifier(newName);
}
}
which I’ve tried using, but hibernate seems to be completely ignoring (a breakpoint in the class never got called).
My current configuration:
<!-- Using Spring XML configuration -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties" ref="hibernateProperties"/>
<property name="annotatedClasses" ref="annotatedClasses"/>
</bean>
<bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean" >
<property name="properties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<!-- I've tried both creating a custom implicit strategy or using an existent one, but they seem to never get called -->
<prop key="hibernate.implicit_naming_strategy">legacy-hbm</prop>
<prop key="hibernate.physical_naming_strategy">net.grouplink.ehelpdesk.dao.hibernate.naming.ImprovedNamingStrategy</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.cache.provider_configuration">classpath:ehcache.xml</prop>
<prop key="hibernate.jdbc.batch_size">15</prop>
<prop key="hibernate.show_sql">${jdbc.showSql}</prop>
<prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.impl.FSDirectoryProvider</prop>
<prop key="hibernate.search.default.indexBase">${hibernate.search.default.indexBase}</prop>
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
</bean>
Current framework versions:
<spring.version>4.3.8.RELEASE</spring.version>
<hibernate.version>5.2.14.Final</hibernate.version>
<oracle.ojdbc.version>11.2.0.3</oracle.ojdbc.version>
Should the naming strategies be passed on differently to the LocalSessionFactoryBean ? Am I missing something?
Thank you very much, and keep leading the defining the ORM world