개발 메모장

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

ORM

[QueryDSL] QueryDSL 사용방법(1)

yyyyMMdd 2024. 1. 30. 18:00
728x90

#. Q타입 호출하기

  • Entity를 생성하고 @Entity 어노테이션을 추가한 뒤 QueryDSL을 build 하면 plugin에서 설정한 경로에 Q타입을 생성할 것입니다.

  • 해당 Q타입 객체를 사용하기 위해 아래 내용을 입력해 줍니다.

  • 또한 jpaQueryFactory 사용을 위해 JPAQueryFactory 또한 선언해 줍니다.

  • custom 한 레파지토리를 사용할 경우 상속 및 해당 customRepository에 선언해 주시면 됩니다.
@Autowired
private JPAQueryFactory jpaQueryFactory;
private QMemberEntity qMember = QMemberEntity.memberEntity;

 


#. fetch를 통한 데이터 반환

 

  • fetch를 이용해 호출한 데이터의 return 결과를 정할 수 있습니다.

  • fetch를 이용한 결과 반환의 경우 보통 5가지로 구분합니다.

1. fetchOne()

- 호출한 데이터가 단건일 때 사용합니다.

- 다건의 데이터를 호출하게 될 경우 오류가 발생(NonUniqueResultException) 합니다.

@GetMapping("fetch")
public void fetchTest() {
	MemberEntity result = jpaQueryFactory.select(qMember)
						.from(qMember)
						.fetchOne();
}

 


2. fetchFirst()

 

- 호출한 데이터들 중 첫 번째 값을 반환합니다.

- 단건이건 다건이건 무조건 첫 번째 값만 반환합니다.

 

- 실행 시 아래와 같이 쿼리를 생성하여 데이터를 조회합니다.

@GetMapping("fetch")
public void fetchTest() {
	MemberEntity result = jpaQueryFactory.select(qMember)
						.from(qMember)
						.fetchFirst();
}

 


3. fetch()

 

- 호출한 데이터들을 List로 반환합니다.

@GetMapping("fetch")
public ResponseEntity<List<MemberEntity>> fetchTest() {
	List<MemberEntity> result = jpaQueryFactory.select(qMember)
							.from(qMember)
							.fetch();
	return ResponseEntity.ok(result);
}

 


4. fetchCount()

 

- 호출한 데이터의 개수를 반환합니다.

- deprecated 되었지만 간단하게 처리할 때 사용가능합니다.

@GetMapping("fetch")
public ResponseEntity<Long> fetchTest() {
	Long result = jpaQueryFactory.select(qMember)
					.from(qMember)
					.fetchCount();
	return ResponseEntity.ok(result);
}

 


5. fetchResults()

- QueryDSL에서 제공하는 리턴타입인 QueryResults를 통해 번들 데이터를 반환받습니다.

- offSet, Total, 호출 데이터 등을 반환받습니다.

- 이 또한 deprecated 되어 거의 사용하진 않습니다.

@GetMapping("fetch")
public ResponseEntity<QueryResults<MemberEntity>> fetchTest() {
	QueryResults<MemberEntity> result = jpaQueryFactory.select(qMember)
								.from(qMember)
								.fetchCount();
	return ResponseEntity.ok(result);
}

 


#. where 절 연산하기

  •  where 조건 인스턴스에 들어갈 연산에 대한 내용으로 and, or, =, !=, berween 등을 표현할 수 있습니다.

1. eq

 

- query에서 =과 같은 역할을 합니다.

@GetMapping("oper")
public ResponseEntity<List<MemberEntity>> operTest(String keyword) {
	List<MemberEntity> eqResult = jpaQueryFactory.selectFrom(qMember)
    							.where(qMember.name.eq("홍글동"))
                        				.fetch();
	return ResponseEntity.ok(eqResult);
}

 


2. ne

- query에서 !=, <>과 같은 역할을 합니다.

@GetMapping("oper")
public ResponseEntity<List<MemberEntity>> operTest(String keyword) {
	List<MemberEntity> neResult = jpaQueryFactory.selectFrom(qMember)
    							.where(qMember.name.ne("홍글동"))
                            				.fetch();
	return ResponseEntity.ok(neResult);
}

 


3. between

- query에서 between과 같은 역할을 합니다.

@GetMapping("oper")
public ResponseEntity<List<MemberEntity>> operTest(String keyword) {
	List<MemberEntity> betResult = jpaQueryFactory.selectFrom(qMember)
    							.where(qMember.age.between(30, 35))
                        				.fetch();
	return ResponseEntity.ok(betResult);
}

 


4. in

- 마찬가지로 in과 같은 역할을 하며 인자 구분은 콤마로 합니다.

@GetMapping("oper")
public ResponseEntity<List<MemberEntity>> operTest(String keyword) {
	List<MemberEntity> inResult = jpaQueryFactory.selectFrom(qMember)
                                			.where(qMember.age.in(34, 35))
                                       			.fetch();
	return ResponseEntity.ok(inResult);
}

 


5. like

- like와 같은 역할을 하며 인자로 String형이 입력되어야 합니다.

- 입력 시 % 기호를 같이 넣어줘야 합니다.

@GetMapping("oper")
public ResponseEntity<List<MemberEntity>> operTest(String keyword) {
	List<MemberEntity> likeResult = jpaQueryFactory.selectFrom(qMember)
    							.where(qMember.name.like("%덕배%"))
                            				.fetch();
	return ResponseEntity.ok(likeResult);
}

 


6. contains

- like와 비슷한 역할을 합니다.

- like 인스턴스에는 %를 직접 처리해야 했으나 contains에선 String 인자에 %%를 붙여줍니다.

@GetMapping("oper")
public ResponseEntity<List<MemberEntity>> operTest(String keyword) {
	List<MemberEntity> containsResult = jpaQueryFactory.selectFrom(qMember)
    							.where(qMember.name.contains("드록"))
                                			.fetch();
	return ResponseEntity.ok(containsResult);
}

 


#. Sorting

  • order by의 역할을 하는 정렬을 처리하는 방법에 대해 알아보도록 하겠습니다.

  • 여느 order by와 동일하게 컬럼.asc, desc로 처리 가능합니다.

  • 해당 컬럼의 null 값이 있을 경우 먼저(nullsFirst()) 또는 마지막(nullsLast())으로 호출하는 인스턴스도 있으니 필요에 따라 사용하시길 바랍니다.
@GetMapping("sort")
public ResponseEntity<List<MemberEntity>> sortTest() {
	List<MemberEntity> result = jpaQueryFactory.selectFrom(qMember)
    						.orderBy(qMember.nickname.desc().nullsFirst())
                            			.fetch();
	return ResponseEntity.ok(result);
}

 


#. Group By & Having

  • query에서 사용하는 group by와 having은 queryFactory의 인스턴스를 이용해 바로 처리가 가능합니다.
  • return 하여 화면에 뿌려주기 위해 ListMap에 담아 처리하였습니다.
@GetMapping("grouping")
public ResponseEntity<List<Map<String, Object>>> groupingTest() {
	List<Tuple> result = jpaQueryFactory.select(qMember.name, qMember.age, qMember.email)
					.from(qMember)
					.groupBy(qMember.age, qMember.email)
					.having(qMember.age.eq(34))
					.orderBy(qMember.age.asc())
					.fetch();
                        
	List<Map<String, Object>> resultMapList = new ArrayList();

	for (Tuple tuple : result) {
		Map<String, Object> resultMap = new HashMap<>();
		resultMap.put("name", tuple.get(qMember.name));
		resultMap.put("ageCount", tuple.get(qMember.age));
		resultMap.put("email", tuple.get(qMember.email));
		resultMapList.add(resultMap);
	}

	return ResponseEntity.ok(resultMapList); 
}

 


#. join

 

  • join 할 테이블을 하나 만들어주기 위해 OrderEntity를 만들어 줍니다.

  • MemberEntity와 동일하기 getter, setter, builder를 생성해 주고 controller에서 insert 하는 로직을 만듭니다.

  • 추가로 jpa를 상속받고 있는 MemberRepository의 제네릭은 MemberEntity이므로 OrderRepository에 새로 상속하였습니다.

  • query에서의 조인과 동일하게 사용할 수 있습니다. 다만 N+1 문제가 발생할 수 있으므로 상황에 따라 fetchJoin()을 사용하시는 것이 좋습니다.
@GetMapping("join")
public ResponseEntity<List<Map<String, Object>>> joinTest() {
	List<Tuple> result = jpaQueryFactory.select(qMember.name, qMember.age, qOrder.name, qOrder.sp)
					.from(qMember)
					.join(qOrder).fetchJoin()
					.on(qMember.id.eq(qOrder.id))
					.fetch();
	List<Map<String, Object>> serializedResult = new ArrayList<>();

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

		serializedResult.add(tupleMap);
	}

	return ResponseEntity.ok(serializedResult);
}

 


#. 함수

 

  • avg, sum, min, max, round, floor, ceil 등 호출한 컬럼값을 기본적으로 제공해 주는 함수를 이용해 쉽게 얻을 수 있습니다.
@GetMapping(value = "func", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<String, Object>> funcTest() {
	List<Tuple> result = jpaQueryFactory.select(qMember.age.avg().round(),
						qMember.age.sum(),
						qMember.age.max(),
						qMember.age.min(),
						qMember.age.count())
						.from(qMember).fetch();
	Tuple tupleResult = result.get(0);

	Map<String, Object> resultMap = new HashMap<>();
	resultMap.put("avg", tupleResult.get(0, Double.class));
	resultMap.put("sum", tupleResult.get(1, Integer.class));
	resultMap.put("max", tupleResult.get(2, Integer.class));
	resultMap.put("min", tupleResult.get(3, Integer.class));
	resultMap.put("count", tupleResult.get(4, Long.class));

	return ResponseEntity.ok(resultMap);
}

 


 

 

 

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

728x90

'ORM' 카테고리의 다른 글

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