若手SEを救いたい社畜の手記

わかすくしゅき

Spring Data Jpaと@Entityを使って複数テーブルで共通の値を親クラスにまとめて、子クラスで継承する方法

2021年1月13日

このページに書いてあること

業務用のシステムを作っていると、DBへのアクセスは非常に一般的な処理で、SpringMVCなんかを使っているとSpring Data Jpaを使ってアクセスするのがよくあるパターンかと思います。

で、DBアクセスをするときによくあるのが、

テーブルがたくさんあるけど、全てのテーブルに共通しているカラムがある。

という状況だと思います。例えば、登録日付・更新日付などが該当しそうです。
このとき、@Entityを使ったコードだとすべてのクラスに同じカラム名のコードが入ってしまうことになります。これは避けるためには共通カラムを親クラスに定義して、差分だけを子クラスが定義してやればよさそうです。

私がこの問題にぶつかったのは、テーブルのカラムは同じだがユーザによって取得先のテーブルを切り替えるという要件ででした。

結論

先に結論を。親Entityクラスの@Entityアノテーションをやめて、@MappedSuperclassを使いましょう。これにより、該当クラスはあるEntityの親クラスであることを通知できます。

これを実現したい

Javaを知っている人なら普通に思いつくと思うのですが、共通要素を親クラスに配置してgetter/setterを用意。子クラス側で差分要素を定義したうえで親クラスを継承。というパターンです。

こんな風にして、共通項目をParentEntityに持っていって実際に使うのはChileEntity1と2みたいな作りだと思います。1と2は別々のテーブルを見ている。

この時通常の@EntityをParentEntityに付与してやろうとすると、うまく動きません。
これはPersistanceの内部での取り扱いに矛盾が生じるためです。 

子Entityのコードは以下のようになります。

import javax.persistence.Entity;
import javax.persistence.Table;

import XXXXX.ParentEntity;

/**
 * 子Entity
 *
 */
@Entity
@Table(name = "テーブル1")
public class ChildEntity extends ParentEntity {
 //空
}

親Entity。7行目に注目。

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

import lombok.Data;

@Entity
@Data
public class ParentUserEntity {

	@Id
	@Column(name = "USER_ID")
	private String userId;
	@Column(name = "INSERT_DATE")
	private String insertDate;
	@Column(name = "UPDATE_DATE")
	private String updateDate;
}

こうすると実現できそうな気がするのですが、親Entityについている@Entityのせいで単一のEntity認定されるため上記のコードは動きません。

これはアノテーションを変えるだけで動くようになります。

@MappedSuperclassを使う

なんてことはありません。先ほどの親Entityを以下のように書き換えます。

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

import lombok.Data;

@MappedSuperclass
@Data
public class ParentUserEntity {

	@Id
	@Column(name = "USER_ID")
	private String userId;
	@Column(name = "INSERT_DATE")
	private String insertDate;
	@Column(name = "UPDATE_DATE")
	private String updateDate;
}

これだけです。

たったこれだけで、@Entityの共通要素を抽出できるので簡単ですね!

  • B!