• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

연관관계가 없는 테이블 조회 질문드립니다.

20.12.23 13:14 작성 조회수 3.61k

0

안녕하세요 영한님. 완강을 한 뒤에도 궁금한 점이 있어서요!

Member.class

@Entity
@Getter
@Setter
public class Member {

@Id
private Long id;
private String name;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "locker_id")
private Locker locker;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "room_id")
private Room room;
}

Locker.class

@Entity
@Getter
@Setter
public class Locker {

@Id
private Long id;
    private String number;
 private String password;

}

Room.class

@Entity
@Getter
@Setter
public class Room {

@Id
private Long id;
private String password;
    private String address;



}

저번 질문을 통해  Locker를 조인하여 Member객체를 반환시키는 쿼리는


em
.createQuery("select m from Member m join fetch m.locker", Member.class)

로 해결 하였습니다!

다만 위의 경우에는 실제 DB에서 member 테이블에 locker_id가 있기에 조회가 가능한걸로 알고 있습니다.

만약, Member테이블에 컬럼이

PK 인 id 하나와 name 만 있고 Locker에 대한 외래키가 없다면 JPQL을 사용한 조인이 불가능 할까요?


em
.createQuery("select m from Member m join fetch m.locker m1 where m1.number like :NUMBER", Member.class)

이렇게 name을 통한 검색을 해보고 싶은데 잘 되지가 않네요..

where 조건 없이 그냥 join fetch만 해보아도

* ORA-00904: "MEMBER0_"."NUMBER": 부적합한 식별자 라고 나와서요..

검색을 통해 QueryDSL 에서는 가능하다고 하는데 영한님 QueryDSL 인강을 들을 단계가 안되어서 한번 여쭈어 봅니다.. ㅜㅜ

그리고 문득 헷갈리는 부분 하나가....

Member 클래스에서

@JoinColumn(name ="locker_id") 에서 locker_id 가 locker 테이블의 locker_id 를 가르키는 것이 아닌

Member 테이블에서의 locker_id 컬럼을 가르키는 것이 맞나요??

@ 추가적으로 위의 3가지 클래스가 이중조인으로 Locker와 Room 모두 Member 의 컬럼중 을 외래키로 받는 경우라면

오라클에서 하듯이 Join ..  on ... join ... on ... 이런식으로

join fetch ... where ...  join fetch ... where ... 이렇게 쿼리를 짜야할까요??

도중에 수정하긴 했지만 질문 자체가 횡설수설 하네요 ㅜㅜ..

긴 질문 글 읽어주셔서 감사합니다!

답변 4

·

답변을 작성해보세요.

1

감사합니다 영한님!!

기본편도 바로 다시 보겠습니다

잊지않고 답변 달아주셔서 감사합니다^^

1

안녕하세요. KwangMin Lee님

먼저 연관관계 매핑이 잘못되었습니다.

MAP_ADM2, MAP_ADM은 N:1 관계입니다.

MAP_ADM2, MAP_CODE는 서로 관계가 없는 코드입니다.

이런 경우는 엔티티로 조회하는 것이 불가능하고, 엔티티로 조회할 수 없기 때문에 JPQL을 작성하더라도 fetch join을 할 수 없습니다. 대신에 JPQL을 사용하더라도 일반 join을 사용하고, 각각의 데이터를 직접 select절에 포함해야 합니다.(a.username, b.xx 등등)

다음 링크의 기본편 13:00에 있는 2. 연관관계 없는 엔티티 외부 조인을 참고해보시면 도움이 되실거에요.

https://www.inflearn.com/course/ORM-JPA-Basic/lecture/21722?tab=curriculum

감사합니다.

1

안녕하세요. KwangMin Lee님

도움을 드리고 싶은데, 제가 명확하게 이해를 하고 답변을 드리는게 좋다 생각합니다. 그래서 힘드시겠지만 질문을 조금 더 구체적으로 적어주시면 좋겠습니다.

1. 저번 질문을 통해  Locker를 조인하여 Member객체를 반환시키는 쿼리는

em.createQuery("select m from Member m join fetch m.locker", Member.class)

로 해결 하였습니다!

다만 위의 경우에는 실제 DB에서 member 테이블에 locker_id가 있기에 조회가 가능한걸로 알고 있습니다.

만약, Member테이블에 컬럼이

PK 인 id 하나와 name 만 있고 Locker에 대한 외래키가 없다면 JPQL을 사용한 조인이 불가능 할까요?

-> 이 경우 연관관계가 어떻게 되는지 예제 코드를 만들어주세요.

2. @JoinColumn(name ="locker_id") 에서 locker_id 가 locker 테이블의 locker_id 를 가르키는 것이 아닌 Member 테이블에서의 locker_id 컬럼을 가르키는 것이 맞나요??

-> 네 맞습니다. Member 테이블의 locker_id를 FK로 하고, 조인시에는 Locker 테이블의 PK와 조인합니다. 만약 Locker 테이블의 PK가 아닌 다른 컬럼과 조인하고 싶으면 referencedColumnName를 사용하시면 됩니다. (그런데 조인은 가급적 PK와 하셔야 합니다.)

3. @ 추가적으로 위의 3가지 클래스가 이중조인으로 Locker와 Room 모두 Member 의 컬럼중 을 외래키로 받는 경우라면

오라클에서 하듯이 Join ..  on ... join ... on ... 이런식으로

join fetch ... where ...  join fetch ... where ... 이렇게 쿼리를 짜야할까요??

-> 이 경우 연관관계가 어떻게 되는지 예제 코드와 그림을 만들어주세요.

0

안녕하세요 영한님 답변 감사합니다!

질문용으로 테이블을 간략하게 올리려고 하다 보니까 조금 수정하면서 약간 말이 꼬였던거 같습니다ㅜㅜ

현재 테이블 입니다. 모두 PK만 지정이 되어있고 FK는 따로 지정이 안되어있습니다.

MAP_ADM2 의 테이블의 ADM_CD2

MAP_ADM의 테이블의 ADM_CD2

MAP_CODE의 테이블의 DONG_CODE

3가지 컬럼이 동일 한 값으로 사용하고 있습니다.

MAP_ADM2의 엔터티 부분입니다.

위의 1번과 3번의 내용을 합쳐서 질문 드리자면


em
.createQuery("select m from Map_Adm2 m join fetch m.map_adm where adm_emd_name like :ADM_EMD_NAME", Map_Adm2.class)
.setParameter("ADM_EMD_NAME", "%"+amd_emd_name+"%")

MAP_ADM2 와 MAP_ADM 두가지만 조인해서 조회하였을때는 원하는 값이 잘 나왔습니다.

이번에는 위의 테이블 3가지를 조회하려고하는데

오라클에서 이렇게 조회가 가능했는데 JPA로 변경하려고 합니다.

위의 fetch조인과 같이 

" select m from Map_Adm2 Join fetch m.map_adm join fetch m.map_code "

이렇게 해보려고 하니 map_code에 대한 @JoinColumn이 없어서 안되는것 같더라고요.

그래서 

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "ADM_CD2")
private Map_Adm map_adm;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "ADM_CD2")
private Map_Code map_code;

이렇게 해보려고 하니  한가지 컬럼에 ADM_CD2 2가지 @JoinColumn 이 안되는걸 알았습니다.

그래서 우선 테스트 할겸 2가지 테이블만 연결해보자 해서

Map_Adm2 엔터티를  이렇게 변경후

public class Map_Adm2 {

@Id
private String ADM_CD;
private String ADM_EMD_NAME;
private String GEO_X;
private String GEO_Y;
private String CRE_USER;
private String CRE_TIME;
private String ADM_CD2;


// @JsonIgnore //조회안되게 하는 어노테이션 주의
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Map_Adm map_adm;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Map_Code map_code;


}

em.createQuery("SELECT m FROM Map_Adm2 m, Map_Code c WHERE m.ADM_CD2 = c.DONG_CODE", Map_Adm2.class)

이렇게 쿼리를 날려보니 이번에는

java.sql.SQLSyntaxErrorException: ORA-00904: "MAP_ADM2X0_"."MAP_CODE_DONG_CODE": 부적합한 식별자

에러가 났습니다.

수업내용과 같이 연관관계가 테이블에 외래키 컬럼이 모두 있는 상태면 모두 @JoinColumn 으로 하여 join fetch 로 여러개 테이블 조인이 가능할 수 있을것 같은데...

위와 같은 경우에 JPA에서 이와 같은 쿼리를 조회 한다면 어떻게 변경해야 할까요?

감사합니다.