添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
近视的砖头  ·  seekbar用法 - OSCHINA - ...·  10 月前    · 
威武的大象  ·  沈阳% - 图片搜索·  1 年前    · 
宽容的铁链  ·  npms·  1 年前    · 

인프런 커뮤니티 질문&답변

갓다귀갓장국님의 프로필 이미지
갓다귀갓장국

작성한 질문수

실전! Querydsl

동적 쿼리 - Where 다중 파라미터 사용

강사님 where 다중 파라미터를 이용한 동적 쿼리 사용에 대한 질문입니다.

해결된 질문

·

4.4K

28

강사님 강의 잘 보고 있습니다.

다름아니라, where 다중 파라미터를 사용하면 가독성이 높아지는 건 이해했습니다.

영상 8분경의 메소드

private BooleanExpression allEq(String userNameCond, Integer ageCond) {

return userNameEq(userNameCond).and(ageEq(ageCond));

에 대한 질문인데요 문제는 userNameCond가 null일 경우 userNameEq가 null을 반환하기 때문에 BooleanExpression으로 체이닝을 할 수가 없는데

혹시 이럴경우 null 걱정없이 강제로 체이닝 하는 방법은 없을까요?

BooleanExpression을 체이닝 하려고 해봤는데 추상클래스라 객체 생성이 안되네요

답변 9

21

김영한님의 프로필 이미지
김영한
지식공유자

갓다귀갓장국님 선물입니다. ㅋㅋㅋ 투척

private BooleanBuilder ageEq(Integer age) {
return nullSafeBuilder(() -> member.age.eq(age));
}

private BooleanBuilder roleEq(String roleName) {
return nullSafeBuilder(() -> member.roleName.eq(roleName));
}

public static BooleanBuilder nullSafeBuilder(Supplier<BooleanExpression> f) {
try {
return new BooleanBuilder(f.get());
} catch (IllegalArgumentException e) {
return new BooleanBuilder();
}
}

자바 8을 공부하시면 이렇게 코드를 더 줄일 수 도 있습니다.

좋은 하루 되세요^^

강사님 nullSafeBuilder 부분도 람다로 고쳐보고싶은데!..

 public static BooleanBuilder NullSafeBuilders(Supplier<BooleanExpression> o ){
       return Optional.ofNullable(o.get()).map(BooleanBuilder::new).orElseGet(BooleanBuilder::new);

이렇게하면 익셉션이뜨더군요,,

그래서  이렇게도 해보았는데 똑같이 안되더군요 .. 람다로 어떻게 풀수있을까요?..

return Optional.ofNullable(o.get()).map(BooleanBuilder::new).orElseThrow(IllegalArgumentException::new);

김영한님의 프로필 이미지
김영한
지식공유자

이 코드를 람다로 풀 이유를 잘 모르겠습니다^^

혹시 아시는 분 있으면 답변 부탁드립니다.

8

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 갓다귀갓장국님 이제 끝이 보이는군요^^

다음 코드를 보시면 대략 어떻게 해야할지 감이 잡히실거에요.

@DataJpaTest
public class DynamicQueryTest {

JPAQueryFactory queryFactory;
@Autowired
EntityManager em;

@BeforeEach
void init() {
queryFactory = new JPAQueryFactory(em);

em.persist(new Member("userA", 10, "ROLE_MASTER"));
em.persist(new Member("userB", 20, "ROLE_ADMIN"));
em.persist(new Member("userC", 30, "ROLE_USER"));
}

@Test
void dynamicQuery() {

// Integer age = 10;
// String role = "ROLE_MASTER";
Integer age = null;
String role = null;

List<Member> result = queryFactory
.selectFrom(member)
.where(ageAndRoleEq(age, role))
.fetch();

System.out.println("result = " + result);

}

private BooleanBuilder ageAndRoleEq(Integer age, String role) {
return ageEq(age).and(roleEq(role));
}

private BooleanBuilder ageEq(Integer age) {
if (age == null) {
return new BooleanBuilder();
} else {
return new BooleanBuilder(member.age.eq(age));
}
}

private BooleanBuilder roleEq(String roleName) {
if (roleName == null) {
return new BooleanBuilder();
}
return new BooleanBuilder(member.roleName.eq(roleName));
}

}

감사합니다.

7

김영한님의 프로필 이미지
김영한
지식공유자

공부공부님 아쉽게도 ExpressionUtils.allOf를 사용해도 null처리는 따로 해주어야 합니다^^

다음 코드를 보시면 이해가 되실꺼에요.

return ExpressionUtils.allOf(member.age.eq(age), member.roleName.eq(roleName));

이렇게 풀어보면 member.age.eq(null) 이렇게 되는데, eq() 자체가 null을 받으면 예외가 발생합니다.

감사합니다.

5

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 참치캔님 하나씩 답변 달아드릴게요.

1. nullSafeBuilder 메서드는 다른 메서드처럼 private 인스턴스로 안 만드시고, public static 메서드로 설계하셨는데 이 부분에 대해서 혹시 설명을 들어볼 수 있을까요??!

-> 아~ 이것은 nullSafeBuilder를 공통으로 사용할 수 있는 유틸리티 클래스로 뽑아서 사용하라는 의미였습니다. 이 코드상에서는 private으로 하셔도 됩니다.

2. nullSafeBuilder 메서드에서catch로 NPE가 아닌 IllegalArgumentException 을 잡으신 이유에 대해서 궁금합니다!

Querydsl이 IllegalArgumentException을 호출합니다. 그래서 해당 예외를 잡았습니다.

public BooleanExpression eq(T right) {
if (right == null) {
throw new IllegalArgumentException("eq(null) is not allowed. Use isNull() instead");
} else {
return eq(ConstantImpl.create(right));
}

혹시 만약 nullSafeBuilder 메서드를 다른 클래스 에서도 사용하려고 만드신거면 nullSafeBuilder 메서드는 어느 클래스나, 패키지에 귀속되는 게 맞을까요..??!!

-> 네 공통으로 적절하게 두시면 됩니다^^ 사실 계층을 명확하게 나눈다면 repository의 구현과 관련된 곳에 두는 것이 좋습니다.