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인 부분은 동적으로 해결할 수 있다.
반응형