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());