🍈

JPAの@OneToManyとは

2022/04/19に公開

@OneToMany(一対多)片方向

属性 説明 ディフォルト値
mappedBy 連関関係のオーナーを選択する
fetch fetch戦略を決める FetchType.LAZY
cascade persistenceの遷移機能
targetEntity type情報を設定する、ほとんど使わない
  • 一対多片方向は一(1)が関係マッピングのオーナーになること。
    • つまり一(1)のオブジェクトからFKを管理すること。
  • 反面テーブルの一対多の関係は常に多の方にFKがある。
  • オブジェクトとテーブルの違いにより反対側のテーブルのFKを管理する特殊な構造
  • この一対多片方向を使うときは必ず@JoinColumn(name="FK")を使用しなければ成らない。そうでないと@JoinTable戦略が基本戦略として使用され中間テーブルを作ってしまう。

Member.java
@Entity // JPAが管理するオブジェクト
@Table(name = "member")
@Getter @Setter
public class Member {
    @Id
    private Long id;
    private String name;
    //片方向関係なのでMemberには何もない
}
Team.java
@Entity
@Setter @Getter
public class Team {
    @Id
    private Long id;
    private String name;

    @OneToMany
    @JoinColumn(name = "team_id") // 1の方でFKを管理する
    private List<Member> members = new ArrayList<>();
}
  • 上の二つのEntityに値を入れてみると
JpaMain.java
    Member member = new Member();
    member.setId(1L);
    member.setName("basic");

    Team team = new Team();
    team.setId(1L);
    team.setName("TeamA");
    // ??
    team.getMembers().add(member);

    manager.persist(member);
    manager.persist(team);
  • 上のコードを実行したときのsql
Hibernate: 
    /* insert jpabasic.Member
        */ insert 
        into
            member
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* insert jpabasic.Team
        */ insert 
        into
            Team
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* create one-to-many row jpabasic.Team.members */ 
	 update
        member 
    set
        team_id=? 
    where
        id=?
  • 何とupdate文が出てる。
  • Entity(Team)が管理するFKが他のテーブル(Member)にあるため
  • 関係マッピングの管理のためUPDATE文が追加で実行される
  • この関係は性能上問題が多い、
  • 1にFKがある事だけでもデメリットになる
  • 使わないほうがいい
  • この関係より多対一双方向を使えばいい

一対多(@OneToMany)双方向

  • 一対多双方向は公式的に存在しないが
  • @JoinColumn(name="FK", insertable=false, updatable=false)
  • を利用して読み取り専用フィールドを作り双方向みたいに使う方法
  • 公式に存在もしない方法だし使わないほうがいい
  • 多対一双方向を使えばいい
Team.java
@Entity
@Setter @Getter
public class Team {
    @Id
    private Long id;
    private String name;

    @OneToMany
    @JoinColumn(name = "team_id") // 1の方でFKを管理する
    private List<Member> members = new ArrayList<>();
}
Member.java
@Entity // JPAが管理するオブジェクト
@Table(name = "member")
@Getter @Setter
public class Member {
    @Id
    private Long id;
    private String name;
    @ManyToOne
    @JoinColumn(name = "team_id", insertable=false, updatable=false)
    private Team team; // 読み取り専用にする
}

次(@OneToOne)

https://zenn.dev/dev_yoon/articles/838e1d0879c513

Discussion