Tengo una configuración simple de spring-jpa donde he configurado Hibernate’s . Esto significa que si mi clase de entidad tiene una variable, Hibernate debería convertirla 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:ImprovedNamingStrategy
userName
user_name
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 Entity:
@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 puede convertir implícitamente la caja de camello en subrayado.
Por favor, guía.
Solución
Gracias por publicar su propia solución. ¡Me ayuda mucho establecer la estrategia de nombres de Hibernate 5!
La propiedad de pre-Hibernate 5.0 parece dividida en dos partes:hibernate.ejb.naming_strategy
hibernate.physical_naming_strategy
hibernate.implicit_naming_strategy
Los valores de estas propiedades no implementan la interfaz como lo hizo . Hay dos nuevas interfaces para estos fines: NamingStrategy
hibernate.ejb.naming_strategy
org.hibernate.boot.model.naming.PhysicalNamingStrategy
org.hibernate.boot.model.naming.ImplicitNamingStrategy
Hibernate 5 proporciona solo una implementación de () que asume que los nombres de identificadores físicos son los mismos que los lógicos.PhysicalNamingStrategy
PhysicalNamingStrategyStandardImpl
Hay varias implementaciones de pero no encontré ninguna equivalente a la anterior. (Véase: ImplicitNamingStrategy
ImprovedNamingStrategy
org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
)
Entonces, implementé el mío propio, que es muy simple:PhysicalNamingStrategy
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 es del original .addUnderscores()
org.hibernate.cfg.ImprovedNamingStrategy
Luego, establecí esta estrategia física en el archivo de persistencia.xml:
<property name="hibernate.physical_naming_strategy" value="my.package.PhysicalNamingStrategyImpl" />
Es una trampa establecer la estrategia de nomenclatura Hibernate 5 como configuración de la versión anterior.
Otras respuestas
Thanks and +1 to Samuel Andrés for the very helpful answer, however it’s probably a good idea to avoid the hand-written snake-casing logic. Here is the same solution, using Guava.
It assumes your entity names are written in the and column names in the StandardJavaClassFormat
standardJavaFieldFormat
Hopefully this will save some people coming here in future some googling 🙂
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()
);
}
}