Spring/QueryDsl

태태개발일지 - QueryDSL

태태코 2024. 9. 29. 18:04
반응형

JOIN PART

 

영한선생님의 querydsl 강의를 보고 조금 정리해본다.

 

@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id","username","age"})
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    private String username;
    private int age;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;
    
    public Member(String username,int age,Team team){
        this.username = username;
        this.age = age;
        
        if(team!=null){
            changeTeam(team);
        }
    }


    public Member(String username) {
        this(username,0,null);
    }


    public Member(String username,int age) {
        this(username,age,null);
    }
    private void changeTeam(Team team) {
        this.team =team;
        team.getMembers().add(this);
    }
}

 

 

 

@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id","name"})
public class Team {
    @Id
    @GeneratedValue
    @Column(name = "team_id")
    private Long id;
    private String name;

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();

    public Team(String name){
        this.name = name;
    }
}

 

 

 

@Entity
@Getter
@Setter
public class Hello  {

    @Id
    @GeneratedValue
    private Long id;
}

 

 

우선 위와같이 Hello는 Member과 Team이랑은 전혀 관계가 없는 Entity이고,

Member와 Team은 서로 1대 다 연관관계를 맺은 Entity이다 이제 조인을 해보자면.

 

  @Test
    public void startJoin() {
        JPAQueryFactory queryFactory = new JPAQueryFactory(em);


        QMemberDto qMemberDto = new QMemberDto(member.username, member.age);

        var findMember = queryFactory
                .select(member)
                .from(member)
                .join(member.team,team)
                .where(member.age.eq(10))
                .fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");

        System.out.println("findmember = "+ findMember.getTeam());
    }

 

원하는 속성만 뽑기 위해서 아래의 DTO를 선언했고, 저번 글의 @QueryProjection를 사용했다. 간략하게 말하면, 연관관계를 맺고있는 엔티티 끼리의 join은 위와같이 .join(연관관계엔티티.연관되어있는엔티티, 연관되어있는엔티티)

이와 같이 사용하면된다.

@Data
@NoArgsConstructor
public class MemberDto {
    private String username;
    private int age;


    @QueryProjection
    public MemberDto(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

 

    @Test
    public void startJoin2() {
        JPAQueryFactory queryFactory = new JPAQueryFactory(em);


        QMemberHelloDto qMemberDto = new QMemberHelloDto(member.username, member.age, QHello.hello.id);

        var findMember = queryFactory
                .select(qMemberDto)
                .from(member)
                .join(QHello.hello).on(member.id.eq(QHello.hello.id))
                .where(member.age.eq(10))
                .fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");

        System.out.println("findmember = "+ findMember);
    }

 

 

 

아래도 마찬가지로 @QueryProjection을 이용했고, Hello와 Member은 아예 연관관계가 없기에, 

.join(엔티티).on(엔티티 필드.비교메서드(다른 엔티티의 필드))

 

@Data
@NoArgsConstructor
public class MemberHelloDto {
    private String username;
    private int age;

    private Long helloId;

    @QueryProjection
    public MemberHelloDto(String username, int age, Long helloId) {
        this.username = username;
        this.age = age;
        this.helloId = helloId;
    }
}

 

 

이와같이 연관관계가 있을 때와 없을 떄로 나누어져있다

left join과 right join 또한 동일하다.

 

// 연관관계가 있을 때 Right Join
JPAQueryFactory queryFactory = new JPAQueryFactory(em);

List<Member> members = queryFactory
    .selectFrom(member)
    .rightJoin(member.team, team)  // 연관관계가 있는 경우 Right Join
    .fetch();

 

 

// 연관관계가 없을 때 Right Join
JPAQueryFactory queryFactory = new JPAQueryFactory(em);

List<Member> members = queryFactory
    .selectFrom(member)
    .rightJoin(team).on(member.teamId.eq(team.id))  // on()으로 조인 조건을 명시
    .fetch();

 

 

이와 별계로 where조건에는 메서드를 통해서 구현할 수 있는데

 

    @Test
    public void startQueryDsl(){
        JPAQueryFactory queryFactory = new JPAQueryFactory(em);
        String name = "member1";
       Member findMember =  queryFactory.select(member)
                .from(member)
                .where(getEq(name))
                .fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }

 

    private static BooleanExpression getEq(String name) {
        return StringUtils.hasText(name)? member.username.eq(name) : null;
    }

 

아래와 같이 메서드를 통해서 해결할 수 있고,

where(methode1(), method2())

이런 방식을 사용하면 null인 부분은 동적으로 해결할 수 있다.

반응형