やる気がストロングZERO

やる気のストロングスタイル

Hibernateでクラステーブル継承を実現する

spring bootでデータアクセスにspring-boot-starter-data-jpa(実装的にはHibernateが使われている)を使っている時、 クラステーブル継承の実現の仕方を理解するのに時間がかかったのでメモ。
[クラステーブル継承]については過去postの中で記載している

参考) Hibernate Inheritance Mapping | Baeldung

※one to one の関連で実現しようと頑張ってたがやり方を間違っていた。普通に継承すればよかった模様。
※下記サンプルコードは個人的都合でEntityではなくMapperという命名を使っている。

データ構成

スーパータイプとしてuserテーブルがあって、サブタイプとしてindividual_user(個人ユーザー)がある。
※ここには記載してないが、サブタイプとして他にcorporate_user(企業ユーザー)があったりする想定

usersテーブル(スーパータイプ)

id created_at updated_at
1 2021-11-11 2021-11-11

individual_usersテーブル(サブタイプ)

user_id name
1 yamada

users.idとindividual_users.user_idがリファレンスキーとなっている。

Entityコード

UserMapper.java

import lombok.Data;

import javax.persistence.*;
import java.time.ZonedDateTime;

@Data // <- getter, setterを書くのがめんどくさいので今回lombokを使っているがintellij曰くJPAEntityでは使わないほうがいいらしい。
@Entity
@Inheritance(strategy = InheritanceType.JOINED)  // <- これでクラステーブル継承であることを指定する
@Table(name = "users")
public class UserMapper {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private ZonedDateTime createdAt;
    private ZonedDateTime updatedAt;

IndividualUserMapper.java

import lombok.Data;

import javax.persistence.*;
import java.time.ZonedDateTime;

@Data // <- getter, setterを書くのがめんどくさいので今回lombokを使っているがintellij曰くJPAEntityでは使わないほうがいいらしい。
@Entity
@PrimaryKeyJoinColumn(name = "userId") // <- これでjoinに使うカラムを指定する
@Table(name = "individual_users")
public class IndividualUserMapper extends UserMapper { // <- 普通に継承する
    private String name;
}

Repositoryコード

import org.springframework.data.jpa.repository.JpaRepository;

public interface IndividualUserInfraRepository extends JpaRepository<IndividualUserMapper, Long> {

使う側

// 保存
var userMapper = new IndividualUserMapper();
userMapper.setName("yamada");
userMapper.setCreatedAt(ZonedDateTime.now());
userMapper.setUpdatedAt(ZonedDateTime.now());
var savedIndividualUser = individualUserInnerRepository.save(userMapper);

// 取得
var loadedIndividualUser = individualUserInnerRepository.findById(savedIndividualUser.getId());