개발 메모장

[QueryDSL] QueryDSL 사용방법(2) 본문

ORM

[QueryDSL] QueryDSL 사용방법(2)

yyyyMMdd 2024. 1. 31. 17:25
728x90

#. 문자열 붙이기(Concat)

 

  • 호출한 데이터들을 하나의 데이터로 연결하여 처리할 수 있는 기능입니다.

  • concat 인스턴스는 String Expression으로 String 값을 인자로 받습니다.

  • 따라서 String이 아닌 값에 대해선 StringValue()로 처리하여야 합니다.

  • toString도 가능하나 객체 형태로 리턴합니다.
@GetMapping("concat")
public ResponseEntity<String> concatTest() {
	String result = jpaQueryFactory.select(qMember.name.concat("-")
								.concat(qMember.nickname)
								.concat("-")
								.concat(qMember.age.stringValue()))
					.from(qMember)
					.where(qMember.name.eq("드록바"))
					.fetchOne();
	return ResponseEntity.ok(result);
}

 


#. 상수 만들기

  • 쿼리를 사용하다 보면 가끔 강제로 데이터를 주는 경우가 있을 것입니다.

  • 이 경우 constant를 이용해 처리하면 됩니다.

  • console에서 보는 쿼리에는 표기되지 않으나 결과를 보면 정상적으로 처리됐습니다.
@GetMapping("const")
public ResponseEntity<Tuple> constTest() {
	Tuple tuple = jpaQueryFactory.select(qMember.nickname, Expressions.constant("캡틴"))
    					.from(qMember)
                   			.fetchFirst();
	return ResponseEntity.ok(tuple);
}

 


#. 서브쿼리

 

  • 서브쿼리의 경우 JPAExpressions를 이용해 처리하면 됩니다.

  • 동일 테이블로 서브쿼리를 만들어야 하는 경우 Q객체를 하나 더 만들어 처리하면 됩니다.

  • 스칼라 서브쿼리를 사용한 데이터를 return 할 때에는 get 할 키값이 명확하지 않기에 아래와 같은 변수 생성 방식으로도 처리가 가능합니다.
@GetMapping("sub")
public ResponseEntity<List<Map<String, Object>>> subTest() {
	// 서브쿼리
	Expression<String> spAlias = JPAExpressions.select(qOrder.sp)
							.from(qOrder)
							.where(qOrder.name.eq("드록바"));

	List<Tuple> result = jpaQueryFactory.select(qMember.name, qMember.email, spAlias)
    					.from(qMember)
					.where(qMember.name.eq(JPAExpressions.select(qOrder.name)
										.from(qOrder)
										.where(qOrder.name.eq("드록바"))))
					.fetch();
                    
	List<Map<String, Object>> resultLast = new ArrayList<>();

	for(Tuple tuple: result) {
		Map<String, Object> tupleMap = new HashMap<>();
		tupleMap.put("name", tuple.get(qMember.name));
		tupleMap.put("email", tuple.get(qMember.email));
		tupleMap.put("sp", tuple.get(spAlias));

		resultLast.add(tupleMap);
	}
	return ResponseEntity.ok(resultLast);
}

 


#. Case문

 

  • 간단한 내용은 case ~ when ~ then으로 처리할 수 있지만 보통 그렇지 않을 것입니다.

  • caseBuilder를 이용해 범위로 처리하는 방법입니다.
@GetMapping("case")
public ResponseEntity<List<Map<String, Object>>> caseTest() {
	List<Tuple> result = jpaQueryFactory.select(new CaseBuilder().when(qMember.age.between(18, 22)).then("유망주")
								.when(qMember.age.between(23, 31)).then("전성기")
								.when(qMember.age.between(32, 40)).then("노장")
								.when(qMember.age.between(41, 60)).then("은퇴")
								.otherwise("X")
								.as("asStatus"),
								qMember.name,
								qMember.age)
                                       		.from(qMember)
                                       		.fetch();
	List<Map<String, Object>> resultListMap = new ArrayList<>();

	for(Tuple tuple : result) {
		Map<String, Object> map = new HashMap<>();
		map.put("status", tuple.get(new CaseBuilder().when(qMember.age.between(18, 22)).then("유망주")
								.when(qMember.age.between(23, 31)).then("전성기")
								.when(qMember.age.between(32, 40)).then("노장")
								.when(qMember.age.between(41, 60)).then("은퇴")
								.otherwise("X")
								.as("asStatus")));
		map.put("name", tuple.get(qMember.name));
		map.put("age", tuple.get(qMember.age));

		resultListMap.add(map);
	}

	return ResponseEntity.ok(resultListMap);
}

 


#. distinct

 

  • 쿼리에서 사용하는 것과 같이 동일하게 사용하면 됩니다.
@GetMapping("dist")
public ResponseEntity<List<Tuple>> dist(String name, Integer age) {
	List<Tuple> result = jpaQueryFactory.select(qMember.name, 
						qMember.age).distinct()
                                             .from(qMember)
                                             .where(qMember.age.eq(34))
                                             .fetch();
	return ResponseEntity.ok(result);
}

 


#. 동적 쿼리

 

1. BooleanBuilder

  • null 체크 후 BooleanBuilder를 통해 and로 해당 값을 이어주는 방식입니다.

  • 전달받은 파라미터가 없을 경우 and를 하지 않아 전달한 파라미터에 대해서만 조건에 추가가 가능해집니다.
@GetMapping("dynamic")
public ResponseEntity<List<MemberEntity>> dynamic(String name, Integer age) {
	BooleanBuilder builder = new BooleanBuilder();
	if(name != null) {
		builder.and(qMember.name.eq(name));
	}
	if(age != null) {
		builder.and(qMember.age.eq(age));
	}

	List<MemberEntity> result = jpaQueryFactory.selectFrom(qMember)
    						.where(builder)
                        			.fetch();
	return ResponseEntity.ok(result);
}

  • 파라미터 1개 입력 시 동작하는 쿼리

  • 파라미터 2개 입력 시 동작하는 쿼리

  • builder를 통해 알아서 처리가 가능합니다.

2. 메서드 이용

  • 전달받은 파라미터를 이용해 booleanExpression을 통해 null인지 값이 있는지 체크하는 방법입니다.
// 아래의 메서드를 생성해주고
private BooleanExpression nameCheck(String name) {
	return name != null ? qMember.name.eq(name) : null;
}

private BooleanExpression ageCheck(Integer age) {
	return age != null ? qMember.age.eq(age) : null;
}

// where 인스턴스에 해당 메서드를 넣어 처리해줍니다.
List<MemberEntity> result = jpaQueryFactory.selectFrom(qMember)
					   .where(nameCheck(name)
                    				, ageCheck(age))
                   			   .fetch();

 


#. update

  • update도 마찬가지로 update ~ set ~ where ~ 와 같은 방식으로 처리합니다.

  • 한 가지 다른 점은 마지막 인스턴스로 execute()를 사용하여 마무리합니다.

  • 이때의 값은 업데이트 처리를 진행한 수를 반환합니다.

  • 또한 상황에 따라 flush 및 clear 시켜줘야 문제없이 사용할 수 있으니 상황에 맞게 처리해 주시길 바랍니다.(@Transactional 사용 시 반드시 flush를 사용할 필요는 없으니 상황에 따라 처리해 주세요.)
    (DB와 관련된 로직이 뒤에서 실행될 경우 clear 하게 되면 문제가 발생할 수 있습니다.)
@Transactional
@PutMapping("updatedsl")
public void update() {
	long count = jpaQueryFactory.update(qMember)
				.set(qMember.age, 28)
				.where(qMember.name.eq("드록바"))
				.execute();
	em.flush();
	// em.clear();
}

 

 


#. delete

 

  • delete 또한 간편하게 처리가 가능합니다.
@Transactional
@DeleteMapping("deletedsl")
public void delete() {
	long count  = jpaQueryFactory.delete(qMember).where(qMember.name.eq("메시")).execute();
}

 


 

 

 

===========================================================
틀린 내용이 있거나 이견 있으시면 언제든 가감 없이 말씀 부탁드립니다!
===========================================================

728x90

'ORM' 카테고리의 다른 글

[QueryDSL] QueryDSL Projection  (0) 2024.02.01
[QueryDSL] QueryDSL 사용방법(1)  (1) 2024.01.30
[JPA] JPA의 정의와 사용 예제  (1) 2024.01.10
[QueryDSL] QueryDSL 정의 및 설정방법  (0) 2024.01.08
[myBatis] myBatis 사용방법  (1) 2023.12.26