47

Hibernate を構成した単純な spring-jpa 構成がありますImprovedNamingStrategy。これは、エンティティ クラスに variable がある場合userName、Hibernate はそれをuser_nameデータベースにクエリするために に変換する必要があることを意味します。しかし、Hibernate 5 にアップグレードした後、この命名変換が機能しなくなりました。次のエラーが表示されます。

エラー: 「フィールド リスト」の不明な列「user0_.userName」

これは私の休止状態の設定です:

@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();
    }
}

これは私のエンティティクラスです:

@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;

}

@Column アノテーション内でデータベース フィールドに明示的に名前を付けたくありません。キャメルケースをアンダースコアに暗黙的に変換できる構成が必要です。

ガイドしてください。

4

8 に答える 8

74

独自のソリューションを投稿していただきありがとうございます。Hibernate 5 の命名戦略を設定するのにとても役立ちます!

Pre-Hibernate 5.0のhibernate.ejb.naming_strategyプロパティは、次の 2 つの部分に分かれているようです。

  • hibernate.physical_naming_strategy
  • hibernate.implicit_naming_strategy

これらのプロパティの値は、実装したようにNamingStrategyインターフェイスを実装しませんhibernate.ejb.naming_strategy。これらの目的のために、2 つの新しいインターフェイスがあります。

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

Hibernate 5 は、物理識別子名が論理識別子名と同じであることを前提とするPhysicalNamingStrategy( ) の実装を 1 つだけ提供します。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);
 }
}

addUnderscores()メソッドはオリジナルのものであることに注意してくださいorg.hibernate.cfg.ImprovedNamingStrategy

次に、この物理戦略を persistence.xml ファイルに設定します。

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

Hibernate 5 の命名規則を以前のバージョンの設定として設定するのはトラップです。

于 2016-01-02T11:08:23.490 に答える
7

非常に役立つ回答を提供してくれた Samuel Andrés に感謝し、+1 しますが、手書きのスネーク ケース ロジックを避けることをお勧めします。Guava を使用した同じソリューションを次に示します。

エンティティ名が に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()
    );
  }
}
于 2016-07-30T10:11:09.787 に答える
2

お役に立てれば:

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

ここにコードがあります(既存のコードから再配置されたばかりです):

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);
    }

}
于 2016-06-29T22:24:54.453 に答える
-8

問題を把握したところ、Hibernate バージョン < 5.0 を使用する場合、構成は完全に問題ありませんが、Hibernate >= 5.0 の場合は問題ありません。

Spring 4.2.0.RELEASEでHibernate 5.0.0.Finalを使用していました。Hibernate 5 は Spring 4.2 と完全には互換性がないと思います。Hibernate を 4.2.1.Final にダウングレードしたところ、問題なく動作し始めました。

Hibernate のNamingStrategyクラスは、Hibernate 5 で廃止されました。

于 2015-09-08T06:54:59.827 に答える