Featured image of post 【ImprovedNamingStrategyは廃止】スネークケースのDBカラムをキャメルケースのEntityフィールドにマッピングする方法【PhysicalNamingStrategyStandardImpl】

【ImprovedNamingStrategyは廃止】スネークケースのDBカラムをキャメルケースのEntityフィールドにマッピングする方法【PhysicalNamingStrategyStandardImpl】

905文字

DBはスネークケース、Entityはキャメルケースにしたい

DBアクセスが伴うシステム等の実装をしている際に、設計方針によってはDB側のTableカラム名はスネークケース、Java側のEntityフィールド名はキャメルケースにしたい、という要望があります。

この際に、全てのEntityフィールドに

AdminEntity.java
@Column(name=:"admin_name")
private String adminName

のようにしても良いが、フィールド数が多かったり変更する際に影響範囲が多かったり課題は沢山あります。

今回はHibernate5系を使っている際にPhysicalNamingStrategyStandardImplを継承して、共通処理としてスネークケースとキャメルケースをマッピング出来るようにしようと思います。

手順

前提

今回は以下のような環境での作業とします。

Point
  • Hibernate: 5.1.0
  • PlayFramework: 2.7
  • MySQL: 5.7

PhysicalNamingStrategyStandardImplの継承クラスの追加

まずは、org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImplを継承したカスタムクラスを実装します。

[adsense-responsive]

db.sample.CustomNamingStrategy.java
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を観てみると、他にもtoPhysicalSchemaNametoPhysicalTableNameメソッドがあるので、必要メソッドだけ@Overrideすれば処理を変える事が出来そうです。

org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl.java
/*
 * 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.xmlhibernate.physical_naming_strategyに上記のクラスを利用するようにプロパティを追加します。

[adsense-responsive]

conf/META-INF/persistence.xml
<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を使っているのであれば便利なクラスや設定が存在します。

同じような課題を抱えている方はぜひ試してみてください♪