HibernateのImprovedNamingStrategy
を設定した簡単なspring-jpa設定があります。つまり、エンティティクラスに変数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();
}
}
これは私の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;
}
@Columnアノテーション内でデータベースフィールドに明示的に名前を付けたくありません。キャメルケースを暗黙的にアンダースコアに変換できる構成が必要です。
ガイドしてください。
独自のソリューションを投稿していただきありがとうございます。 Hibernate 5の命名戦略を設定するのに非常に役立ちます!
Hibernate 5.0より前の_hibernate.ejb.naming_strategy
_プロパティは、2つの部分に分かれているようです。
hibernate.physical_naming_strategy
_hibernate.implicit_naming_strategy
_これらのプロパティの値は、_hibernate.ejb.naming_strategy
_のようにNamingStrategy
インターフェイスを実装しません。これらの目的のための2つの新しいインターフェイスがあります。
org.hibernate.boot.model.naming.PhysicalNamingStrategy
_org.hibernate.boot.model.naming.ImplicitNamingStrategy
_Hibernate 5は、物理識別子名が論理識別子名と同じであると想定するPhysicalNamingStrategy
(PhysicalNamingStrategyStandardImpl
)の実装を1つだけ提供します。
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の命名戦略を以前のバージョン設定として設定することはトラップです。
非常に有用な回答をありがとう、サミュエル・アンドレスに+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()
);
}
}
その投稿をありがとう。このアップグレードが少しいらいらするだけでは、テーブルと列の名前の戦略が崩れます。 ImprovedNamingStrategy
からロジックをコピーする代わりに、委任を使用することもできます。
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);
}
}
すべての回答はPhysicalNamingStrategy
を実装することでソリューションを投稿しますが、必要な(そして行うべき)ことはImplicitNamingStrategy
を実装することだけです。
エンティティがマップ先のデータベーステーブルに明示的に名前を付けない場合、そのテーブル名を暗黙的に決定する必要があります。または、特定の属性がマップ先のデータベース列に明示的に名前を付けていない場合、その列名を暗黙的に決定する必要があります。マッピングで明示的な名前が提供されなかった場合に論理名を決定するためのorg.hibernate.boot.model.naming.ImplicitNamingStrategyコントラクトの役割の例があります。
そして、コードはこれと同じくらい簡単にすることができます(他の回答と同じように元のaddUnderscores
を使用します):
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);
}
}
お役に立てれば:
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);
}
}
グアバと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()
);
}
}