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

조재연님의 프로필 이미지
조재연

작성한 질문수

실전! Querydsl

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

안녕하세요. query에 대해 질문이 있습니다.

작성

·

855

0

안녕하세요. 기존 MyBatis에서는

<where>

         <if test="name != null and name != ''">

               name LIKE concat('%', '#{name}, '%')

        </if>

       <if test="loc != null and loc != ''">

               OR loc LIKE concat('%', #{loc}, '%')

      </if>

</where>

ORDERY BY deptno DESC

이런 쿼리문이 있는데요. 공학이 포함된 이름만 보여주는 걸 짜고 있는데요. 기존 강의에서 conatains()를 하면 like '%member%' 이렇게 된다고 알려주셨는데

이런경우는 contains() 로 하고 or절로 하는게 괜찮을까요? 아니면 where 다중 파라미터로 하는게 나을까요..

제가 먼저 다중파라미터로 해보고 있는데요. 예제에서는 

String usernameParam = "XXX";

Integer ageParam = 10; 

이런식으로 한개만 먼저 하셨는데 

미리 사전데이터 입력같은 경우는 어떻게 해야될지 모르겠어서 질문드립니다. ㅜ

(Test 파일에다가 assertThat 테스트 하려고 미리 넣어둔 데이터 입니다.)

@BeforeEach
public void before() {
queryFactory = new JPAQueryFactory(em);
Department department1 = new Department("컴퓨터공학과", "103");
Department department2 = new Department("정보통신공학과", "103");
Department department3 = new Department("음악과", "104");
Department department4 = new Department("국어국문과", "104");
em.persist(department1);
em.persist(department2);
em.persist(department3);
em.persist(department4);

답변 4

1

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

안녕하세요. 재연님

도움을 드리고 싶은데, 정확하게 어떤 SQL을 원하시는지를 먼저 파악이 필요합니다.

다음을 준비해주세요.

1. DDL

2. 테스트 데이터 INSERT SQL

3. 원하는 최종 SELECT SQL 

4. 최종 결과에서 나온 데이터

감사합니다.

1

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

안녕하세요. 재연님

바로 전 강의에서 Builder를 사용하는데요. 이것을 활용해서 or를 적용하시면 됩니다.

감사합니다.

조재연님의 프로필 이미지
조재연
질문자

감사합니다 !

0

조재연님의 프로필 이미지
조재연
질문자

안녕하세요 강사님. JPA부터 다시 복습하고 오느냐 우선 중단하고 다시 연관관계부터 하면서 좀 늦었습니다 !

위에 제가 질문했던 size에 관한건 이해가 다 됐습니다 ! 근데 다른 질문이 있습니다.

제가 사전 데이터를 이렇게 집어 넣었구요.

강사님꺼 전에 강의 다시 들어보면서 참고 많이 되었습니다.

그래서 쿼리를 보면

/* select

        professor 

    from

        Professor professor 

    where

        professor.username = ?1 

        or professor.position like ?2 escape '!' */

result = [Professor(id=5, userid=null, position=교수, sal=0, hiredate=null),

Professor(id=6, userid=null, position=교수, sal=0, hiredate=null)]

이렇게 result로 출력결과 봤을 때 '교수' 라고 되어 있는 값만 나오는것도 확인을 했습니다.

그리고 공부하다 보니 like vs contains 에 대해도 알게 되었습니다.

@Test
void dynamicQuery4() throws Exception {

String nameParam = "공학";
String nameParam2 = "공학";

List<Department> result = searchDepartment4(nameParam, nameParam2);
System.out.println("result = " + result);
}

private List<Department> searchDepartment4(String nameCond, String locCond) {

return queryFactory
.selectFrom(department)
.where(
departmentEq(nameCond)
.or(departmentLike(locCond)))
.orderBy(department.id.desc())
.fetch();
}

private BooleanExpression departmentEq(String nameCond) {
return nameCond != null ? department.name.eq(nameCond) : null;
}

private BooleanExpression departmentLike(String locCond) {
return !StringUtils.hasText(locCond) ? null : department.loc.contains("공학");
}

1) 여기서 제가 궁금한건 검증작업을 assertThat 으로 작성해서 할 때 교수라는 position 만 가지고 있는 사람만 OK 하고 싶은데요. 이걸 찾아보니

이렇게 하면 professor1, professor2 이쪽에 오류가 발생해서 이렇게 하는건 아닌거 같아서 

assertThat(result).filterOn(professor) <- 이렇게 해보았는데도 'professor1 ->' , 'QProfessor' 이렇게 밖에 안나오더라구요. 그래서 어떤방법으로 해야되는지 잘 모르겠습니다.

assertThat(result).extracting("position").containsExactly(professor1, professor2);
@BeforeEach
void before() throws Exception {

queryFactory = new JPAQueryFactory(em);

Department departmentA = new Department("정보통신공학과", "101");
Department departmentB = new Department("컴퓨터공학과", "102");
Department departmentC = new Department("음악과", "103");
Department departmentD = new Department("국어국문과", "104");
em.persist(departmentA);
em.persist(departmentB);
em.persist(departmentC);
em.persist(departmentD);

Professor professor1 = new Professor("김교수", "교수", departmentA);
Professor professor2 = new Professor("박교수", "교수", departmentA);
Professor professor3 = new Professor("조교수", "부교수", departmentB);
Professor professor4 = new Professor("최교수", "부교수", departmentC);
Professor professor5 = new Professor("이교수", "전임강사", departmentD);
em.persist(professor1);
em.persist(professor2);
em.persist(professor3);
em.persist(professor4);
em.persist(professor5);

}


@Test
void dynamicQuery3() throws Exception {

String nameParam = "김교수";
String positionParam = "교수";

List<Professor> result = searchDepartment3(nameParam, positionParam);
assertThat(result.size()).isEqualTo(2);
System.out.println("result = " + result);

}

private List<Professor> searchDepartment3(String nameCond, String positionCond) {

return queryFactory
.selectFrom(professor)
.where(
nameEq(nameCond)
.or(positionLike(positionCond)))
.fetch();
}

private BooleanExpression nameEq(String nameCond) {
return nameCond != null ? professor.username.eq(nameCond) : null;
}

private BooleanExpression positionLike(String positionCond) {
return !StringUtils.hasText(positionCond) ? null : professor.position.like(positionCond);

}


2)  여기서 like 와 contains 의 차이점도 알게되었는데요.

여기서 결과값을 보면 result = [] 아무것도 안나오는데 이유를 잘 모르겠습니다..!

@Test
void dynamicQuery4() throws Exception {

String nameParam = "공학";
String nameParam2 = "공학";

List<Department> result = searchDepartment4(nameParam, nameParam2);
System.out.println("result = " + result);
}

private List<Department> searchDepartment4(String nameCond, String locCond) {

return queryFactory
.selectFrom(department)
.where(
departmentEq(nameCond)
.or(departmentLike(locCond)))
.orderBy(department.id.desc())
.fetch();
}

private BooleanExpression departmentEq(String nameCond) {
return nameCond != null ? department.name.eq(nameCond) : null;
}

private BooleanExpression departmentLike(String locCond) {
return !StringUtils.hasText(locCond) ? null : department.loc.contains("공학");
}


1) DDL

CREATE TABLE DEPARTMENT (

int(4) deptno NotNULL PRI

varchar(16) dname NotNULL 

varchar(100) loc 

)

CREATE TABLE PROFESSOR (

int(11) profno NotNull PRI

varchar(50) name NotNull

varchar(50) userid NotNull

varchar(20) position NotNull

int(10) sal NotNull

datetime hiredate NotNull

int(11) comm

int(11) deptno NotNull MUL

)

3) 원하는 최종 SELECT SQL

SELECT deptno, dname, loc FROM department

WHERE dname LIKE conat('%', '공학', '%')

ORDERY BY deptno DESC

입니다.

감사합니다.

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

안녕하세요. 조재연님

번거로우시겠지만 새로운 질문은 새로 다시 작성 부탁드립니다.

그래야 다른 분들에게도 도움이 되고, 서포터즈 분들도 함께 도와드릴 수 있습니다.

1) Q: 여기서 제가 궁금한건 검증작업을 assertThat 으로 작성해서 할 때 교수라는 position 만 가지고 있는 사람만 OK 하고 싶은데요. 이걸 찾아보니

-> 너무 복잡하게 푸는 것 보다 단순하게 for 루프로 해당하는 내용이 있는지 찾은 다음에 검증하면 될 듯 합니다.

2) 이 부분은 실행시 어떤 로그가 나오는지 어떤 JPQL와 SQL이 수행되는지 보시면 이해가 되실꺼에요.

만약 로그를 보고도 이해가 잘 안되시면, 해당 부분을 새로운 질문으로 올려주세요. 질문을 올리실 때는 최대한 많은 정보와 로그, JPQL, SQL도 같이 올려주세요.

감사합니다.

조재연님의 프로필 이미지
조재연
질문자

안녕하세요.  강사님

답변 감사합니다.

새로운 질문은 새로 작성하겠습니다. 

감사합니다.

0

조재연님의 프로필 이미지
조재연
질문자

안녕하세요. 강사님

제가 개인적으로 해보다가 질문이 있어서 다시 남기게 되었습니다.

제가 이런식으로 해보았는데요. 

쿼리도

/* select

        department 

    from

        Department department 

    where

        department.name = ?1 

        or department.name = ?2 

        or department.name = ?3 

        or department.name = ?4 

        or department.loc = ?5 */

이렇게 다 나가구요.

/* select department

from Department department

where department.name = '컴퓨터공학과'1 or department.name = '정보통신공학과'2 or department.name = '음악과'3 or department.name = '국어국문과'4 or department.loc = '104호'5 */

이렇게 해서 assertThat(result.size()).isEqualTo(5)); 로 하면

org.opentest4j.AssertionFailedError: 

expected: 5

but was : 4

Expected :5

Actual   :4

4라고 나오더라구요. 저는 왜 4인지 잘 모르겠습니다. ㅜ 

감사합니다.

@Test
void testDepartment() throws Exception {

String nameParam1 = "컴퓨터공학과";
String nameParam2 = "정보통신공학과";
String nameParam3 = "음악과";
String nameParam4 = "국어국문과";
String locParam = "104";

List<Department> result = searchDepartment(nameParam1, nameParam2, nameParam3, nameParam4, locParam);
assertThat(result.size()).isEqualTo(5);

}

private List<Department> searchDepartment(String nameParam1, String nameParam2, String nameParam3, String nameParam4, String locParam) {

BooleanBuilder builder = new BooleanBuilder();

if (nameParam1 != null) {
builder.or(department.name.eq(nameParam1));
}

if (nameParam2 != null) {
builder.or(department.name.eq(nameParam2));
}

if (nameParam3 != null) {
builder.or(department.name.eq(nameParam3));
}

if (nameParam4 != null) {
builder.or(department.name.eq(nameParam4));
}

if (locParam != null) {
builder.or(department.loc.eq(locParam));
}

return queryFactory
.selectFrom(department)
.where(builder)
.fetch();
}
조재연님의 프로필 이미지
조재연

작성한 질문수

질문하기