이번 게시물은 JPA를 사용할 때 querydsl 없이 여러 엔티티를 join 하는 방법이다.

단 조건으로 엔티티 중 다른 엔티티 간의 중개자 역할을 하는 엔티티가 필요하다 매핑이 되어 있어야 한다.

코드로 보자

@Entity
public class Company {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "company", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name = "company_id")
    private List<Product> products = new ArrayList<>();

    @OneToOne(mappedBy = "company", fetch = FetchType.LAZY)
    private Employee employee;

}

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id")
    private Company company;
    
}

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

}

이 코드를 보면 Company는 2개의 다른 엔티티와 연결돼있는 상태이다.

이 상태에서 본다면 Product와 Employee는 서로 관계가 없는 엔티티처럼 보이지만

Company라는 중개자 엔티티를 통해 서로 연결이 가능하다.

사용방법은 이러하다 밑의 레포지토리를 보자.

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {

    List<Employee> findByCompany_Products_Name(String productsName);

}

위의 코드를 보면 레포지토리는 EmployeeRepository이다.

메서드를 보면 findBy 후에 Employee에 있는 Company를 불러오고 _를 사용해 Company 안에 있는 Products를 불러온다.

그 후 _를 사용해 Product 안의 name까지 불러온다. 그렇게 해서 완성된 메서드는 findByCompany_Products_Name이다

이렇게 메서드가 작성되면 실행되는 쿼리는 Product의 name을 찾는 쿼리를 만든다

결과는 다음과 같다.

Hibernate: 
    select
        employee0_.id as id1_1_,
        employee0_.company_id as company_3_1_,
        employee0_.name as name2_1_ 
    from
        employee employee0_ 
    left outer join
        company company1_ 
            on employee0_.company_id=company1_.id 
    left outer join
        product products2_ 
            on company1_.id=products2_.company_id 
    where
        products2_.name=?

employee로 시작해서 company를 left outer join 그리고 product를 left outer join 해서 product name을 찾는 걸 볼 수 있다.

단 사용에 주의할 점은 엔티티 내부에 매핑을 잘해줘야 한다는 것이다.

만약 저 상태에서 Company에 Product가 없고 Product 엔티티 안에 단방향으로 돼있을 경우에는 안된다.

- 끗 -

image