ImprovedNamingStrategy不再适用于Hibernate 5

Anu*_*nup 38 java hibernate jpa spring-data-jpa hibernate-5.x

我有简单的spring-jpa配置,我配置了Hibernate ImprovedNamingStrategy.这意味着如果我的实体类有一个变量userName,那么Hibernate应该将它转换user_name为查询数据库.但是在我升级到Hibernate 5后,这个命名转换停止了工作.我收到错误:

错误:"字段列表"中的未知列'user0_.userName'

这是我的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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的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;

}
Run Code Online (Sandbox Code Playgroud)

我不想在@Column注释中明确命名我的数据库字段.我想要我的配置可以隐式地将驼峰转换为下划线.

请指导.

小智 63

感谢您发布自己的解决方案.设置Hibernate 5命名策略对我有很大的帮助!

hibernate.ejb.naming_strategypre-Hibernate 5.0 的属性似乎分为两部分:

  • hibernate.physical_naming_strategy
  • hibernate.implicit_naming_strategy

这些属性的值不像那样实现NamingStrategy接口hibernate.ejb.naming_strategy.有两个用于这些目的的新接口:

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

Hibernate 5仅提供PhysicalNamingStrategy(PhysicalNamingStrategyStandardImpl)的一个实现,假定物理标识符名称与逻辑标识符相同.

有几个实现,ImplicitNamingStrategy但我发现没有相当于旧的ImprovedNamingStrategy.(参见:org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl)

所以,我实现了自己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);
 }
}
Run Code Online (Sandbox Code Playgroud)

请注意,该addUnderscores()方法来自原始方法org.hibernate.cfg.ImprovedNamingStrategy.

然后,我将此物理策略设置为persistence.xml文件:

  <property name="hibernate.physical_naming_strategy" value="my.package.PhysicalNamingStrategyImpl" />
Run Code Online (Sandbox Code Playgroud)

将Hibernate 5命名策略设置为先前版本设置是一个陷阱.

  • 同样,连同自定义物理命名策略,属性“ hibernate.implicit_naming_strategy”可以设置为“ org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl” (2认同)
  • 伟大的答案塞缪尔,它应该是正确的,而不是另一个.有谁知道他们为什么改变了这种行为?它对我来说毫无意义 (2认同)
  • Spring Boot 1.4更新:您现在可以使用Spring的[SpringPhysicalNamingStrategy](http://docs.spring.io/spring-boot/docs/1.4.0.RC1/api/org/springframework/boot/orm/jpa/hibernate/ SpringPhysicalNamingStrategy.html)(yml):`spring.jpa.properties.hibernate.physical_naming_strategy:org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy` (2认同)

man*_*cia 13

代替

jpaProperties.put("hibernate.ejb.naming_strategy",
                  "org.hibernate.cfg.ImprovedNamingStrategy");
Run Code Online (Sandbox Code Playgroud)

更改为新的物理命名策略和新的实现CamelCaseToUnderscoresNamingStrategy,其行为与旧的相同ImprovedNamingStrategy

jpaProperties.put("hibernate.physical_naming_strategy",
                  "org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy");
Run Code Online (Sandbox Code Playgroud)

在 Hibernate 5.6.1.FINAL 中可用


dav*_*wil 5

非常感谢塞缪尔·安德烈斯(SamuelAndrés)的+1并为他提供了非常有用的答案,但是避免手写蛇形套管逻辑可能是个好主意。这是使用番石榴的相同解决方案。

假设您的实体名称写在中的StandardJavaClassFormat和列名称中standardJavaFieldFormat

希望这可以节省一些将来来这里搜索的人:-)

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()
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Anu*_*nup -8

刚刚解决了这个问题,当使用 Hibernate 版本 < 5.0 时配置绝对没问题,但对于 Hibernate >= 5.0 则不行。

我使用 Hibernate 5.0.0.Final 和 Spring 4.2.0.RELEASE。我猜想 Hibernate 5 与 Spring 4.2 不完全兼容。我刚刚将 Hibernate 降级到 4.2.1.Final,一切开始正常。

Hibernate 的NamingStrategy类在 Hibernate 5 中已弃用。