Edited at

Spring Data JPA において、@OneToMany に targetEntity = RelatedClass.class を指定した際の挙動について

More than 1 year has passed since last update.


概要

先日何気なく Spring Data JPA のエンティティをリファクタリングしていた時にしくっていることを発見したので、その備忘録です。

こんなリレーションがあったとします。


|---------------
|Company
| id
| employee_id
|---------------
1
|
n
|------------
|Employee
| id
| name
|---------------


Company.java

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

@NoArgsConstructor
@Getter
@Embeddable
public abstract class Company {
@Id
private Integer id;

@OneToMany(targetEntity = Employee.class, fetch = FetchType.EAGER)
@PrimaryKeyJoinColumn
protected Set<Employee> employees;
}



Employee.java

@Entity

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Getter
@NoArgsConstructor
public abstract class Employee {
@Id
private int id;

@Column(name = "employee_id", insertable = false, updatable = false)
private int employeeId;

@ManyToOne
private Company company;
}


これらのエンティティ (とその他雑多なエンティティ) に対して JPQL を実行したところ、下記のような SQL が実行されました。


select
distinct many columns...
from
company company3_
left outer join
company_employees employees4_
on company3_.id = employees4_.company_id
left outer join
employee employee5_
on employees4_.employees_id = employee5_.id

どうやら、下記のように、JPA では、Company と Employee の関係が ManyToMany の関係があるものとして認識されているようでした。。


|---------------
|Company
| id
| employee_id
|---------------
1
|
n
|------------
|Company_Employees
| company_id
| employee_id
|---------------
n
|
1
|------------
|Employee
| id
| name
|---------------


動作の要因について

Company の @OneToMany にて targetEntity 属性で関連を定義していたため、上記動作になったようです。

継承戦略を多用しているので、どうしてもそのような形になってしまうのかと考えていた (要因の一端ではある気がします) のですが、関連を通常の mappedBy に変更することで実行される SQL が変わりました。


Company.java

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

@NoArgsConstructor
@Getter
@Embeddable
public abstract class Company {
@Id
private Integer id;

@OneToMany(mappedBy = "company", fetch = FetchType.EAGER)
@PrimaryKeyJoinColumn
protected Set<Employee> employees;
}



Employee.java

@Entity

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Getter
@NoArgsConstructor
public abstract class Employee {
@Id
private int id;

@Column(name = "employee_id", insertable = false, updatable = false)
private int employeeId;

@ManyToOne
private Company company;
}


実行される SQL。

select

distinct many columns...
from
company company3_
left outer join
employee employee5_
on company3_.id = employee5_.company_id