DBはスネークケース、Entityはキャメルケースにしたい
DBアクセスが伴うシステム等の実装をしている際に、設計方針によってはDB側のTableカラム名はスネークケース、Java側のEntityフィールド名はキャメルケースにしたい、という要望があります。
この際に、全てのEntityフィールドに
@Column(name=:"admin_name")
private String adminName
のようにしても良いが、フィールド数が多かったり変更する際に影響範囲が多かったりと課題は沢山あります。
今回はHibernate5系を使っている際にPhysicalNamingStrategyStandardImplを継承して、共通処理としてスネークケースとキャメルケースをマッピング出来るようにしようと思います。
手順
前提
今回は以下のような環境での作業とします。
- Hibernate: 5.1.0
- PlayFramework: 2.7
- MySQL: 5.7
PhysicalNamingStrategyStandardImplの継承クラスの追加
まずは、org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImplを継承したカスタムクラスを実装します。
package db.sample;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import com.google.common.base.CaseFormat;
public class CustomNamingStrategy extends PhysicalNamingStrategyStandardImpl {
@Override
public Identifier toPhysicalColumnName(
final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
private Identifier convertToSnakeCase(final Identifier identifier) {
final String entityField = identifier.getText();
String formattedEntityField = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entityField);
return Identifier.toIdentifier(formattedEntityField);
}
}
文字列をキャメルケースからスネークケースに変換するのは自前で行うとちょっとめんどくさいので、今回はGoogleが提供しているライブラリを利用しました。
カラム名以外にも処理を追加する事が可能
org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl.javaを観てみると、他にもtoPhysicalSchemaNameやtoPhysicalTableNameメソッドがあるので、必要メソッドだけ@Overrideすれば処理を変える事が出来そうです。
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.boot.model.naming;
import java.io.Serializable;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
/**
* Standard implementation of the PhysicalNamingStrategy contract.
*
* @author Steve Ebersole
*/
public class PhysicalNamingStrategyStandardImpl implements PhysicalNamingStrategy, Serializable {
/**
* Singleton access
*/
public static final PhysicalNamingStrategyStandardImpl INSTANCE = new PhysicalNamingStrategyStandardImpl();
@Override
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment context) {
return name;
}
@Override
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment context) {
return name;
}
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return name;
}
@Override
public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment context) {
return name;
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return name;
}
}
hibernate.physical_naming_strategyの追加
次に、presistence.xmlのhibernate.physical_naming_strategyに上記のクラスを利用するようにプロパティを追加します。
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<non-jta-data-source>DefaultDS</non-jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="org.hibernate.flushMode" value="COMMIT"/>
<property name="hibernate.physical_naming_strategy" value="repositories.db.CustomNamingStrategy" /> <!-- 追加 -->
</properties>
</persistence-unit>
</persistence>
これで@Columnアノテーションを使わなくても、DBのスネークケースのカラムをEntityのキャメルケースのフィールドに自動でマッピングするようになります。
終わりに
以上のように、Hibernateを使っているのであれば便利なクラスや設定が存在します。
同じような課題を抱えている方はぜひ試してみてください♪
