strategy java hibernate jpa spring-data-jpa hibernate-5.x

java - hibernate naming strategy



La estrategia de nombres mejorada ya no funciona en Hibernate 5 (7)

Tengo una configuración simple de spring-jpa donde configuré ImprovedNamingStrategy de Hibernate. Esto significa que si mi clase de entidad tiene una variable userName , Hibernate debería convertirla en user_name para consultar la base de datos. Pero esta conversión de nombres dejó de funcionar después de actualizar a Hibernate 5. Recibo el error:

ERROR: columna desconocida ''user0_.userName'' en ''lista de campos''

Esta es mi configuración de Hibernate:

@Configuration @EnableJpaRepositories("com.springJpa.repository") @EnableTransactionManagement public class DataConfig { @Bean public DataSource dataSource(){ DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/test"); ds.setUsername("root"); ds.setPassword("admin"); return ds; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(){ HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setShowSql(Boolean.TRUE); vendorAdapter.setDatabase(Database.MYSQL); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(vendorAdapter); factory.setDataSource(dataSource()); factory.setPackagesToScan("com.springJpa.entity"); Properties jpaProperties = new Properties(); jpaProperties.put("hibernate.ejb.naming_strategy","org.hibernate.cfg.ImprovedNamingStrategy"); jpaProperties.put("hibernate.dialect","org.hibernate.dialect.MySQL5InnoDBDialect"); factory.setJpaProperties(jpaProperties); factory.afterPropertiesSet(); return factory; } @Bean public SharedEntityManagerBean entityManager() { SharedEntityManagerBean entityManager = new SharedEntityManagerBean(); entityManager.setEntityManagerFactory(entityManagerFactory().getObject()); return entityManager; } @Bean public PlatformTransactionManager transactionManager() { JpaTransactionManager txManager = new JpaTransactionManager(); txManager.setEntityManagerFactory(entityManagerFactory().getObject()); return txManager; } @Bean public ImprovedNamingStrategy namingStrategy(){ return new ImprovedNamingStrategy(); } }

Esta es mi clase de entidad:

@Getter @Setter @Entity @Table(name="user") public class User{ @Id @GeneratedValue private Long id; private String userName; private String email; private String password; private String role; }

No quiero nombrar explícitamente los campos de mi base de datos dentro de las anotaciones @Column. Quiero mi configuración que implícitamente puede convertir el caso de camello en subrayado.

Por favor guía.


Acabo de resolver el problema, la configuración es absolutamente buena cuando se usa una versión de Hibernate <5.0 pero no para Hibernate> = 5.0.

Estaba usando Hibernate 5.0.0.Final con Spring 4.2.0.RELEASE. Supongo que el Hibernate 5 no es totalmente compatible con Spring 4.2. Acabo de bajar Hibernate a 4.2.1. Final y las cosas comenzaron a funcionar bien.

La clase NamingStrategy de Hibernate está en desuso en Hibernate 5.


Cada respuesta publica una solución implementando PhysicalNamingStrategy , pero todo lo que necesita (y debe hacer) es implementar ImplicitNamingStrategy .

Cuando una entidad no nombra explícitamente la tabla de la base de datos a la que se asigna, necesitamos determinar implícitamente ese nombre de tabla. O cuando un atributo particular no nombra explícitamente la columna de la base de datos a la que se asigna, necesitamos determinar implícitamente ese nombre de columna. Hay ejemplos del rol del contrato org.hibernate.boot.model.naming.ImplicitNamingStrategy para determinar un nombre lógico cuando la asignación no proporcionó un nombre explícito.

Y el código puede ser tan fácil como esto (usando los addUnderscores originales como en otras respuestas):

public class ImplicitNamingStrategyImpl extends ImplicitNamingStrategyJpaCompliantImpl { @Override protected Identifier toIdentifier(String stringForm, MetadataBuildingContext buildingContext) { return super.toIdentifier(addUnderscores(stringForm), buildingContext); } protected static String addUnderscores(String name) { final StringBuilder buf = new StringBuilder(name.replace(''.'', ''_'')); for (int i = 1; i < buf.length() - 1; i++) { if (Character.isLowerCase(buf.charAt(i - 1)) && Character.isUpperCase(buf.charAt(i)) && Character.isLowerCase(buf.charAt(i + 1))) { buf.insert(i++, ''_''); } } return buf.toString().toLowerCase(Locale.ROOT); } }


Gracias por publicar su propia solución. ¡Me ayuda mucho establecer la estrategia de nombres de Hibernate 5!

La propiedad hibernate.ejb.naming_strategy de pre-Hibernate 5.0 parece dividida en dos partes:

  • hibernate.physical_naming_strategy
  • hibernate.implicit_naming_strategy

Los valores de estas propiedades no implementan la interfaz NamingStrategy como hibernate.ejb.naming_strategy . Hay dos nuevas interfaces para estos fines:

  • org.hibernate.boot.model.naming.PhysicalNamingStrategy
  • org.hibernate.boot.model.naming.ImplicitNamingStrategy

Hibernate 5 proporciona solo una implementación de PhysicalNamingStrategy ( PhysicalNamingStrategyStandardImpl ) que supone que los nombres de los identificadores físicos son los mismos que los lógicos.

Hay varias implementaciones de ImplicitNamingStrategy pero no encontré ninguna equivalente a la antigua ImprovedNamingStrategy . (Ver: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl )

Entonces, implementé mi propia PhysicalNamingStrategy que es muy simple:

public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable { public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl(); @Override public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) { return new Identifier(addUnderscores(name.getText()), name.isQuoted()); } @Override public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) { return new Identifier(addUnderscores(name.getText()), name.isQuoted()); } protected static String addUnderscores(String name) { final StringBuilder buf = new StringBuilder( name.replace(''.'', ''_'') ); for (int i=1; i<buf.length()-1; i++) { if ( Character.isLowerCase( buf.charAt(i-1) ) && Character.isUpperCase( buf.charAt(i) ) && Character.isLowerCase( buf.charAt(i+1) ) ) { buf.insert(i++, ''_''); } } return buf.toString().toLowerCase(Locale.ROOT); } }

Tenga en cuenta que el método addUnderscores() es del org.hibernate.cfg.ImprovedNamingStrategy original.

Luego, configuro esta estrategia física en el archivo persistence.xml:

<property name="hibernate.physical_naming_strategy" value="my.package.PhysicalNamingStrategyImpl" />

Es una trampa establecer la estrategia de nombres de Hibernate 5 como configuración de la versión anterior.


Sin utilidades de guayaba y apache

public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl { public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) { return context.getIdentifierHelper().toIdentifier( name.getText().replaceAll("((?!^)[^_])([A-Z])", "$1_$2").toLowerCase(), name.isQuoted() ); } public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) { return context.getIdentifierHelper().toIdentifier( name.getText().replaceAll("((?!^)[^_])([A-Z])", "$1_$2").toLowerCase(), name.isQuoted() ); } }


espero que esto ayude:

hibernate.implicit_naming_strategy = .... ImplicitNamingStrategy hibernate.physical_naming_strategy = .... PhysicalNamingStrategyImpl

y aquí está el código (solo reordenado del código existente):

import java.io.Serializable; import java.util.Locale; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable { public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl(); @Override public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) { return new Identifier(addUnderscores(name.getText()), name.isQuoted()); } @Override public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) { return new Identifier(addUnderscores(name.getText()), name.isQuoted()); } protected static String addUnderscores(String name) { final StringBuilder buf = new StringBuilder( name.replace(''.'', ''_'') ); for (int i=1; i<buf.length()-1; i++) { if ( Character.isLowerCase( buf.charAt(i-1) ) && Character.isUpperCase( buf.charAt(i) ) && Character.isLowerCase( buf.charAt(i+1) ) ) { buf.insert(i++, ''_''); } } return buf.toString().toLowerCase(Locale.ROOT); } }


gracias por ese post Poco molesto que la actualización rompe la tabla y la estrategia de nombre de columna. En lugar de copiar la lógica de ImprovedNamingStrategy , también podría usar la delegación.

public class TableNamingStrategy extends PhysicalNamingStrategyStandardImpl { private static final String TABLE_PREFIX = "APP_"; private static final long serialVersionUID = 1L; private static final ImprovedNamingStrategy STRATEGY_INSTANCE = new ImprovedNamingStrategy(); @Override public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) { return new Identifier(classToTableName(name.getText()), name.isQuoted()); } @Override public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) { return new Identifier(STRATEGY_INSTANCE.classToTableName(name.getText()), name.isQuoted()); } private String classToTableName(String className) { return STRATEGY_INSTANCE.classToTableName(TABLE_PREFIX + className); } }


Gracias y +1 a Samuel Andrés por la útil respuesta , sin embargo, probablemente sea una buena idea evitar la lógica de la carcasa de la serpiente escrita a mano. Aquí está la misma solución, usando guayaba.

Asume que los nombres de sus entidades están escritos en StandardJavaClassFormat y los nombres de columna en standardJavaFieldFormat

Espero que esto ahorre a algunas personas que vienen aquí en el futuro a buscar en Google :-)

import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import static com.google.common.base.CaseFormat.*; public class SnakeCaseNamingStrategy extends PhysicalNamingStrategyStandardImpl { public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) { return new Identifier( UPPER_CAMEL.to(LOWER_UNDERSCORE, name.getText()), name.isQuoted() ); } public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) { return new Identifier( LOWER_CAMEL.to(LOWER_UNDERSCORE, name.getText()), name.isQuoted() ); } }