このページに書いてあること
業務用のシステムを作っていると、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の共通要素を抽出できるので簡単ですね!