[Spring_Boot] queryDSL 활용(2)

최현석·2022년 12월 16일
0

Spring_Boot

목록 보기
31/31

Main

			Member member1 = new Member("member1",10,teamA);
			Member member2 = new Member("member2",20,teamA);
			Member member3 = new Member("member3",30,teamB);
			Member member4 = new Member("member4",40,teamB);
			Member member5 = new Member(null,100,teamB);
			Member member6 = new Member("member6",100,teamB);
			Member member7 = new Member("member7",100,teamB);
			em.persist(member1);
			em.persist(member2);
			em.persist(member3);
			em.persist(member4);
			em.persist(member5);
			em.persist(member6);
			em.persist(member7);

🧩 조인

연관관계가 있는 필드로 조인

  • join -> inner join을 기본으로 가져온다.
			List<Member> result = queryFactory
									.selectFrom(member)
									// member에 있는 team과 실제 team을 조인
									.join(member.team, team) 
									.fetch();
			System.out.println(result.toString());
  • 결과
  • 쿼리문

세타조인

  • 연관관계가 없는 필드로 조인
  • 회원의 이름이 팀 이름과 같은 회원 조회
			em.persist(new Member("teamA"));
			em.persist(new Member("teamB"));
			
			List<Member> result2 = queryFactory
									.select(member)
                                    // 연관관계가 없다는 가정하에 두개를 가져온다.
									.from(member, team)
									.where(member.username.eq(team.name))
									.fetch();
			
			System.out.println(result2.toString());
  • 결과
  • 쿼리문

회원과 팀을 조인하면서, 팀 이름이 teamA인 팀만 조인, 회원은 모두 조회

			/*
			 * SQL : 	select 	m.*, t.*
			 * 			from 	member m
			 * 					left outer join Team t 
			 * 						on m.team_id = t.team_id and t.name = 'teamA'
			 */
			
			List<Tuple> result3 = queryFactory
									.select(member, team)
									.from(member)
                                    .leftjoin(member.team, team).on(team.name.eq("teamA"))
									.join(member.team, team).on(team.name.eq("teamA"))
									.fetch();
			
			for(Tuple tuple : result3) {
				System.out.println("tuple : " + tuple);
			}

  • leftjoin 결과
  • 쿼리
  • join 결과

🧩 서브쿼리

  • 나 자신을 가져다 쓸 때는 객체를 하나 더 만들어준다.
			/*
			 * 나이가 가장 많은 회원
			 */
			QMember memberSub = new QMember("memberSub");
			
			List<Member> result = queryFactory
									.selectFrom(member)
									.where(member.age.eq(
										JPAExpressions.select(memberSub.age.max())
														.from(memberSub)
											))
									.fetch();
			
			System.out.println("result : " + result.get(0).getAge());
			
			
			List<Member> result2 = queryFactory
									.selectFrom(member)
									.where(member.age.in(
										JPAExpressions.select(memberSub.age.max())
														.from(memberSub)
											))
									.fetch();

			System.out.println("result2 : " + result2.get(0).getAge());
  • 결과
  • 쿼리

🧩 case 문

			List<String> result = queryFactory
									.select(member.age
										.when(10).then("열살")
										.when(20).then("스무살")
										.otherwise("기타")
										)
									.from(member)
									.fetch();
			for(String s: result) {
				System.out.println("s : " + s);
				
			}
  • 결과
  • 쿼리

🧩 상수, 문자 더하기

  • stringValue() : 문자로 바꾼다.
			List<Tuple> result2 = queryFactory
									.select(member.username, Expressions.constant("A"))
									.from(member)
									.fetch();
			for(Tuple s: result2) {
				System.out.println("Tuple : " + s);
            }
            
			// concat
			// {username}_{age}
			// stringValue() : 문자로 바꾼다.
			List<String> result3 = queryFactory
							.select(member.username.concat("_").concat(member.age.stringValue()))
							.from(member)
							.fetch();
			System.out.println("Tuple : " + result3);
  • 결과
  • 쿼리
    • Expressions.constant("A")) 여기는 쿼리문으로 나오지 않는다.
  • concat결과
  • 쿼리

🧩 결과 반환, 필드 & 생성자 접근, 별칭이 다를 때

  • ExpressionUtils.as(source, alias) : 필드나, 서브쿼리에 별칭 적용
    • 서브쿼리는 반드시 ExpressionUtils.as를 사용
  • username.as("memberName") : 필드에 별칭 적용
			// 대상이 하나.
			List<String> result = queryFactory
									.select(member.username)
									.from(member)
									.fetch();
			
			// 대상이 둘 이상일 때 사용
			List<Tuple> result2 = queryFactory
									.select(member.username,member.age)
									.from(member)
									.fetch();

jpql

			List<MemberDTO> result3 = em.createQuery(
					"select new com.koreait.querydsl.dto.MemberDTO(m.username, m.age)"
					, MemberDTO.class)
					.getResultList();

queryDSL

프로퍼티 접근 -> setter 접근 방법

  • bean
  • 첫번째 param : type지정(ex, MemberDTO.class)
  • 두번쨰 param : 꺼내올 값 나열
  • bean으로 접근하는 방식이기 떄문에 getter, setter 반드시 존재 해야한다.
			List<MemberDTO> result4 = queryFactory
										.select(Projections.bean(MemberDTO.class,
												member.username,member.age))
										.from(member)
										.fetch();

필드 직접 접근

  • getter, setter 없어도 된다.
			
			List<MemberDTO> result5 = queryFactory
										.select(Projections.fields(MemberDTO.class,
												member.username,member.age))
										.from(member)
										.fetch();

생성자 접근, 별칭이 다를 때

  • 알기만해도 된다.
			List<UserDTO> result6 = queryFactory
										.select(Projections.fields(UserDTO.class,
												member.username.as("name"),
												member.age))
										.from(member)
										.fetch();
			
			for(UserDTO userdto : result6) {
				System.out.println("userDTO : " + userdto);
			}

서브쿼리 별칭

  • ExpressionUtils : 필드나, 서브쿼리 이름 줄 떄
  • 나 자신에게 결과값을 준다. -> QMember mSub = new QMember("mSub");

			QMember mSub = new QMember("mSub");
			
			List<UserDTO> result7 = queryFactory
										.select(Projections.fields(UserDTO.class,
												member.username.as("name"),
												ExpressionUtils.as(
													JPAExpressions
														.select(mSub.age.max())
														.from(mSub),"age")
												))
										.from(member)
										.fetch();
					
					for(UserDTO userdto : result7) {
					System.out.println("userDTO : " + userdto);
					}

  • mSub 별칭이 다르면 값이 담기지 않지만 as사용해서 alias를 줘서 사용

🧩 동적 쿼리 - BooleanBuilder 사용

  • searchMember 메서드에 파라미터값을 넣어주는데, 파라미터 값이 있을 때, 없을 때가 있다.
  • 이 조건을 넘겨 받아서 null일 떄는 추가, null이 아닐 때는 추가 해주지 않는다.
			...
try{
			...
			em.flush();
			em.clear();


			String usernameParam = "member1";
			Integer ageParam = 10;
			
			List<Member> result = searchMember(usernameParam, ageParam);
			System.out.println("result.size() : " + result.size());
			 
	}
}
	private static List<Member> searchMember(String usernameParam, Integer ageParam){
		BooleanBuilder builder = new BooleanBuilder();
		if(usernameParam != null) {
			builder.and(member.username.eq(usernameParam));
		}
		
		if(ageParam != null) {
			builder.and(member.age.eq(ageParam));
		}
		System.out.println("builder : " + builder.toString());
		return queryFactory
				.selectFrom(member)
				.where(builder)
				.fetch();
	}
}
  • 쿼리
  • ?, ? 로 조건식이 2개 들어왔다


  • usernameParam = null 로 바꾸면 age 1개만 들어온다


  • 결과

0개의 댓글