월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨실전! Querydsl
페이징 처리 질문
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]지금 질문은 querydsl 뿐만 아니라 spring data jpa도 섞여있습니다. 여태 Spring Data JPA로 페이징을 처리할 때는Page<BoardEntity> findAllByItemItemId(Long itemId, Pageable pageable); @Query(value = "select b from board b " + " join fetch b.member " + " join fetch b.item " + "where b.item.itemId = :itemId" + " order by b.boardId desc ", countQuery = "select count(b) from board b where b.item.itemId = :itemId") Page<BoardEntity> findAllByItemItemId(@Param("itemId") Long itemId, Pageable pageable);이렇게 처리하고서비스에서 // 상품에 대한 문의글 보기 @Transactional(readOnly = true) @Override public Page<BoardDTO> getBoards(Pageable pageable, Long itemId, String email) { // 회원 조회 MemberEntity findUser = memberRepository.findByEmail(email); log.info("유저 : " + findUser); // 상품 조회 ItemEntity findItem = itemRepository.findById(itemId) .orElseThrow(EntityNotFoundException::new); log.info("상품 : " + findItem); // 조회해올 게시글을 넣을 곳 Page<BoardEntity> findAllBoards = boardRepository.findAllByItemItemId(itemId, pageable); // 댓글이 있으면 답변완료, 없으면 미완료 for(BoardEntity boardCheck : findAllBoards) { if(boardCheck.getCommentEntityList().isEmpty()) { boardCheck.changeReply(ReplyStatus.REPLY_X); } else { boardCheck.changeReply(ReplyStatus.REPLY_O); } } for (BoardEntity boardEntity : findAllBoards) { // 파라미터로 받아온 이메일이 있다면 if (email != null) { // 해당 게시글을 만들때 이메일과 조회한 이메일을 체크 // 그리고 맞다면 읽을 권한주고 없으면 잠가주기 if (boardEntity.getMember().getEmail().equals(findUser.getEmail())) { boardEntity.changeSecret(BoardSecret.UN_LOCK); } else { boardEntity.changeSecret(BoardSecret.LOCK); } } else { boardEntity.changeSecret(BoardSecret.LOCK); } } log.info("조회된 게시글 수 : {}", findAllBoards.getTotalElements()); log.info("조회된 게시글 : {}", findAllBoards); return findAllBoards.map(board -> BoardDTO.toBoardDTO( board, board.getMember().getNickName(), board.getItem().getItemId())); } // 상품에 대한 문의글 전체 보기 @GetMapping("") @Tag(name = "board") @Operation(summary = "문의글 전체 보기", description = "모든 상품에 대한 문의글을 봅니다.") public ResponseEntity<?> getBoards( // SecuritConfig에 Page 설정을 한 페이지에 10개 보여주도록 // 설정을 해서 여기서는 할 필요가 없다. @PageableDefault(sort = "boardId", direction = Sort.Direction.DESC) Pageable pageable, @PathVariable(name = "itemId") Long itemId, @RequestParam(value = "email", required = false) String email) { try { log.info("email : " + email); // 검색하지 않을 때는 모든 글을 보여준다. Page<BoardDTO> boards = boardService.getBoards(pageable, itemId, email); Map<String, Object> response = new HashMap<>(); // 현재 페이지의 아이템 목록 response.put("items", boards.getContent()); // 현재 페이지 번호 response.put("nowPageNumber", boards.getNumber()+1); // 전체 페이지 수 response.put("totalPage", boards.getTotalPages()); // 한 페이지에 출력되는 데이터 개수 response.put("pageSize", boards.getSize()); // 다음 페이지 존재 여부 response.put("hasNextPage", boards.hasNext()); // 이전 페이지 존재 여부 response.put("hasPreviousPage", boards.hasPrevious()); // 첫 번째 페이지 여부 response.put("isFirstPage", boards.isFirst()); // 마지막 페이지 여부 response.put("isLastPage", boards.isLast()); return ResponseEntity.ok().body(response); } catch (Exception e) { return ResponseEntity.badRequest().build(); } }이렇게 처리를 했습니다. Page 기능을 사용해서 구현했고 querydsl에서 페이징처리는 다음과 같이 했습니다. @Override public Page<MemberTeamDTO> searchPageComplex(MemberSearchCondition condition, Pageable pageable) { List<MemberTeamDTO> content = queryFactory .select(new QMemberTeamDTO( member.id.as("memberId"), member.userName, member.age, team.id.as("teamId"), team.name.as("teamName"))) .from(member) .leftJoin(member.team, team) .where(userNameEq(condition.getUserName()), teamNameEq(condition.getTeamName()), ageGoe(condition.getAgeGoe()), ageLoe(condition.getAgeLoe())) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch(); // count 쿼리 (조건에 부합하는 로우의 총 개수를 얻는 것이기 때문에 페이징 미적용) long total = queryFactory // SQL 상으로는 count(member.id)와 동일 .select(member.count()) .from(member) // .leftJoin(member.team, team) .where(userNameEq(condition.getUserName()), teamNameEq(condition.getTeamName()), ageGoe(condition.getAgeGoe()), ageLoe(condition.getAgeLoe())) .fetchOne(); return new PageImpl<>(content, pageable, total); }fetchResult와 fetchCount가 지원을 안한다고 해서 조건에 따라 카운트를 구해서 총 개수를 구해서 하는 방식으로 했는데 이렇게 했을 때도 Map<String, Object> response = new HashMap<>(); // 현재 페이지의 아이템 목록 response.put("items", boards.getContent()); // 현재 페이지 번호 response.put("nowPageNumber", boards.getNumber()+1); // 전체 페이지 수 response.put("totalPage", boards.getTotalPages()); // 한 페이지에 출력되는 데이터 개수 response.put("pageSize", boards.getSize()); // 다음 페이지 존재 여부 response.put("hasNextPage", boards.hasNext()); // 이전 페이지 존재 여부 response.put("hasPreviousPage", boards.hasPrevious()); // 첫 번째 페이지 여부 response.put("isFirstPage", boards.isFirst()); // 마지막 페이지 여부 response.put("isLastPage", boards.isLast());이런식으로 뽑아서 프론트에 보낼 수 있는지와실무에서도 spring data jpa와 querydsl 방식으로 페이징 처리를 할 때 이렇게 하는지 아니면 다른 방식이 더있는지 궁금해서 질문드립니다.
- 해결됨실전! Querydsl
Hello 테이블 생성 안됨..
안녕하세요.. Hello Table이 생성이 안돼서 질문 드립니다. 모든 코드는 강의자료에 있는 코드를 복붙했습니다. (에러가 나서 ..) test코드를 돌려보면 에러는 안나는데 h2db테이블에서 생성이 안됩니다.에러 코드 > Task :compileJava UP-TO-DATE > Task :processResources > Task :classes > Task :compileTestJava > Task :processTestResources NO-SOURCE > Task :testClasses > Task :test 15:47:24.714 [Test worker] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [study.querydsl.QuerydslApplicationTests]: QuerydslApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. 15:47:24.762 [Test worker] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration study.querydsl.QuerydslApplication for test class study.querydsl.QuerydslApplicationTests . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.2.0) 2024-01-02T15:47:24.972+09:00 INFO 14318 --- [ Test worker] s.querydsl.QuerydslApplicationTests : Starting QuerydslApplicationTests using Java 17.0.6 with PID 14318 (started by gaheechoi in /Users/gaheechoi/Desktop/휴학/백앤드/querydsl) 2024-01-02T15:47:24.973+09:00 INFO 14318 --- [ Test worker] s.querydsl.QuerydslApplicationTests : No active profile set, falling back to 1 default profile: "default" 2024-01-02T15:47:25.274+09:00 INFO 14318 --- [ Test worker] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2024-01-02T15:47:25.285+09:00 INFO 14318 --- [ Test worker] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 7 ms. Found 0 JPA repository interfaces. 2024-01-02T15:47:25.532+09:00 INFO 14318 --- [ Test worker] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2024-01-02T15:47:25.557+09:00 INFO 14318 --- [ Test worker] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.3.1.Final 2024-01-02T15:47:25.573+09:00 INFO 14318 --- [ Test worker] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled 2024-01-02T15:47:25.685+09:00 INFO 14318 --- [ Test worker] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer 2024-01-02T15:47:25.700+09:00 INFO 14318 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2024-01-02T15:47:25.796+09:00 INFO 14318 --- [ Test worker] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced user=SA 2024-01-02T15:47:25.797+09:00 INFO 14318 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2024-01-02T15:47:25.908+09:00 INFO 14318 --- [ Test worker] p6spy : #1704178045908 | took 3ms | statement | connection 1| url jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced select * from INFORMATION_SCHEMA.SEQUENCES select * from INFORMATION_SCHEMA.SEQUENCES; 2024-01-02T15:47:26.178+09:00 INFO 14318 --- [ Test worker] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) 2024-01-02T15:47:26.186+09:00 DEBUG 14318 --- [ Test worker] org.hibernate.SQL : drop table if exists hello cascade 2024-01-02T15:47:26.187+09:00 INFO 14318 --- [ Test worker] p6spy : #1704178046187 | took 0ms | statement | connection 2| url jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced drop table if exists hello cascade drop table if exists hello cascade ; 2024-01-02T15:47:26.187+09:00 DEBUG 14318 --- [ Test worker] org.hibernate.SQL : drop sequence if exists hello_seq 2024-01-02T15:47:26.187+09:00 INFO 14318 --- [ Test worker] p6spy : #1704178046187 | took 0ms | statement | connection 2| url jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced drop sequence if exists hello_seq drop sequence if exists hello_seq; 2024-01-02T15:47:26.189+09:00 DEBUG 14318 --- [ Test worker] org.hibernate.SQL : create sequence hello_seq start with 1 increment by 50 2024-01-02T15:47:26.191+09:00 INFO 14318 --- [ Test worker] p6spy : #1704178046191 | took 1ms | statement | connection 3| url jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced create sequence hello_seq start with 1 increment by 50 create sequence hello_seq start with 1 increment by 50; 2024-01-02T15:47:26.192+09:00 DEBUG 14318 --- [ Test worker] org.hibernate.SQL : create table hello (id bigint not null, primary key (id)) 2024-01-02T15:47:26.194+09:00 INFO 14318 --- [ Test worker] p6spy : #1704178046194 | took 1ms | statement | connection 3| url jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced create table hello (id bigint not null, primary key (id)) create table hello (id bigint not null, primary key (id)); 2024-01-02T15:47:26.195+09:00 INFO 14318 --- [ Test worker] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2024-01-02T15:47:26.268+09:00 WARN 14318 --- [ Test worker] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning 2024-01-02T15:47:26.478+09:00 INFO 14318 --- [ Test worker] s.querydsl.QuerydslApplicationTests : Started QuerydslApplicationTests in 1.645 seconds (process running for 2.13) 2024-01-02T15:47:26.801+09:00 DEBUG 14318 --- [ Test worker] org.hibernate.SQL : select next value for hello_seq 2024-01-02T15:47:26.803+09:00 INFO 14318 --- [ Test worker] p6spy : #1704178046803 | took 0ms | statement | connection 4| url jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced select next value for hello_seq select next value for hello_seq; 2024-01-02T15:47:26.974+09:00 DEBUG 14318 --- [ Test worker] org.hibernate.SQL : insert into hello (id) values (?) 2024-01-02T15:47:26.976+09:00 INFO 14318 --- [ Test worker] p6spy : #1704178046976 | took 0ms | statement | connection 4| url jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced insert into hello (id) values (?) insert into hello (id) values (1); 2024-01-02T15:47:26.986+09:00 DEBUG 14318 --- [ Test worker] org.hibernate.SQL : select h1_0.id from hello h1_0 2024-01-02T15:47:26.987+09:00 INFO 14318 --- [ Test worker] p6spy : #1704178046987 | took 0ms | statement | connection 4| url jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced select h1_0.id from hello h1_0 select h1_0.id from hello h1_0; 2024-01-02T15:47:27.014+09:00 INFO 14318 --- [ Test worker] p6spy : #1704178047014 | took 0ms | rollback | connection 4| url jdbc:h2:mem:a21f98cc-44fd-4380-bad2-49c71d2c5ced ; OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended 2024-01-02T15:47:27.025+09:00 INFO 14318 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2024-01-02T15:47:27.026+09:00 INFO 14318 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2024-01-02T15:47:27.027+09:00 INFO 14318 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. > Task :test Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. For more on this, please refer to https://docs.gradle.org/8.5/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. BUILD SUCCESSFUL in 3s 4 actionable tasks: 3 executed, 1 up-to-date 3:47:27 PM: Execution finished ':test --tests "study.querydsl.QuerydslApplicationTests"'. h2 db는 기존의 1.4 xx 대를 사용하다, spring boot3로 올리면서 강의자료 대로 2.2.224로 바꾸었습니다.db 생성은 잘 되었고, tcp로 db접근도 완료 했습니다.생성이 안되는 이유를 모르겠습니다 ㅠㅠ... tcp 접근 QHello 위치 application.yml
- 해결됨실전! Querydsl
Q파일 생성 위치 질문
안녕하세요현재 프로젝트 세팅 및 테스트를 진행 중입니다. spring boot가 3이상으로 제한된 상황속에서 진행중이며, 강의 내용을 따라하고 있습니다! build.gradle은 https://docs.google.com/document/d/1j0jcJ9EoXMGzwAA2H0b9TOvRtpwlxI5Dtn3sRtuXQas/edit#heading=h.vfy9wirpglmx를 복/붙 하였습니다.plugins { id 'java' id 'org.springframework.boot' version '3.2.0' id 'io.spring.dependency-management' version '1.1.4' } group = 'study' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //test 롬복 사용 testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' //Querydsl 추가 implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" } tasks.named('test') { useJUnitPlatform() } clean { delete file('src/main/generated') } 질문은 크게 3가지입니다. build/other/compileQuerydsl은 표기가 안되는데 다른 답변을 보니 springboot3으로 올라가며 compileQuerydsl은 표기가 안된다고 하신 것 같은데 맞을까요?정확한 Q파일의 생성 위치가 궁굼합니다.!강의상에서는 src/main에 둬도 괜찮지만, 버전관리 시스템(git)에는 추가 되지 않는게 좋다고 하셨던 것 같은데 맞나요?build에만 Q파일이 생성되는게 좋나요?올려주신 google doc의 build.gradle로 진행하면, Q파일이 build/annotationProcessor아래 생성됩다... 뭐가 문제일까요? docs에 올려주신 build.gradle에서 build clean을 진행할 때 'src/main/generated'의 폴더를 삭제하는 이유가 무엇일까요? (현재 저는 Q파일을 build/ 아래 관리하고있는데, src/main/generate 아래 Q파일을 생성하시는 분들에만 해당 되는 내용인가요?)답변해주시면 감사하겠습니다!
- 미해결실전! Querydsl
compileQuerydsl없음
안녕하세요현재 프로젝트 세팅부터 막혀서 질문 드립니다.질문은 크게 3가지입니다. build 잘됨Gradle Tasks other compileQuerydsl -> 없음 ( spring boot3이상으로 되면서 안보이는게 맞나요)? build.gradleplugins { id 'java' id 'org.springframework.boot' version '3.2.0' id 'io.spring.dependency-management' version '1.1.4' } group = 'study' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //test 롬복 사용 testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' //Querydsl 추가 implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" } tasks.named('test') { useJUnitPlatform() } def querydslSrcDir = 'src/main/generated' clean { delete file(querydslSrcDir) } tasks.withType(JavaCompile) { options.generatedSourceOutputDirectory = file(querydslSrcDir) } https://docs.google.com/document/d/1j0jcJ9EoXMGzwAA2H0b9TOvRtpwlxI5Dtn3sRtuXQas/edit위의 docs 설정만 build.gradle에 기입하면 src/main/generated가 생성이 안되는데 이유가 뭔가용??build폴더 말고, main/generated폴더에 Q파일이 생성되었는데 잘못 생성된건가요.? 답변 주시면 감사하겠습니다.. 추가로,, 현재 build.gradle에 $buildDir은 사용이 안된다고 하네요..!
- 해결됨실전! Querydsl
gradle .gradle폴더 차이
안녕하세요!프로젝트 세팅을 하고 test파일을 실행해보니,gradle폴더와 .gradle폴더가 생성된 것을 확인했습니다. 혹시 두개의 폴더가 무슨 차이가 있나요?out 폴더에는 무슨 폴더고 어떤것들이 들어가나요? 답변 해 주시면 감사하겠습니다!
- 미해결실전! Querydsl
DB결과가 다릅니다.
에러 없이 수행은 됩니다하지만 sql문에서는 제대로 실행되지 않고 있습니다.
- 미해결실전! Querydsl
Q hello가 작성되질 않습니다.
Q hello가 작성되질 않습니다. 다른 내용들을 참고해서 이것저것 설정을 해보았으나 외부라이브러리에 querydsl은 생성되었으나. generarted에는 큐쿼리가 생성되지 않습니다.
- 미해결실전! Querydsl
수업 예제에서 fetch join을 하지 않아도 team.name을 가져오는 이유
안녕하세요.제가 이해한 바로는, join과 fetch join의 차이가 select하는 범위의 차이라고 알고 있습니다.예를 들어,Member findMember = queryFactory .selectFrom(member) .join(member.team, team) .where(member.username.eq("member1")) .fetchOne();위 코드는 일반 join으로 team 연관관계를 조회합니다.그 결과 member 정보만 select 합니다.select m1_0.member_id, m1_0.age, m1_0.team_id, m1_0.username from member m1_0 join team t1_0 on t1_0.team_id=m1_0.team_id where m1_0.username=? 반대로 fetch join을 하면 한 번의 쿼리로 team 정보도 select문에 포함시킵니다.Member findMember = queryFactory .selectFrom(member) .join(member.team, team).fetchJoin() .where(member.username.eq("member1")) .fetchOne();select m1_0.member_id, m1_0.age, t1_0.team_id, t1_0.name, //팀 이름이 추가! m1_0.username from member m1_0 join team t1_0 on t1_0.team_id=m1_0.team_id where m1_0.username=? 여기까지 제가 이해한 게 맞다면, 질문 드립니다.강사님께서 Querydsl에서 where절 파라미터 사용하는 예제를 보여주실 때, 분명 코드는 leftJoin(), 즉 일반 join()을 사용하셨습니다.public List<MemberTeamDto> searchByWhere(MemberSearchCondition condition) { return queryFactory .select(new QMemberTeamDto ( member.id.as("memberId"), member.username, member.age, team.id.as("teamId"), team.name.as("teamName") )) .from(member) .leftJoin(member.team, team) .where( usernameEq(condition.getUsername()), teamnameEq(condition.getTeamName()), ageGoe(condition.getAgeGoe()), ageLoe(condition.getAgeLoe())) .fetch(); }fetch join을 사용하지 않았으니 member와 연관관계를 가진 team은 프록시 객체를 가질 것입니다. 하지만 쿼리문을 보면 마치 fetch join을 한 것처럼 select 문에 team.name을 조회하는 쿼리문이 포함되어 있습니다./* select member1.id as memberId, member1.username, member1.age, team.id as teamId, team.name as teamName from Member member1 left join member1.team as team where team.name = ?1 and member1.age >= ?2 */ select m1_0.member_id, m1_0.username, m1_0.age, t1_0.team_id, t1_0.name from member m1_0 left join team t1_0 on t1_0.team_id=m1_0.team_id where t1_0.name=? and m1_0.age>=? 어째서 fetch join을 하지 않았는데 한 번의 쿼리문으로 member와 team 정보를 모두 조회할 수 있는지 궁금합니다.만약 일반 join으로 가능하다면 굳이 fetch join을 사용할 이유가 없을텐데 말입니다. 감사합니다!
- 해결됨실전! Querydsl
테스트 코드 EntityManager Autowired 컴파일 에러 질문드립니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]build.gradle 설정은 아래와 같이 하였습니다.빌드를 하니 build 경로에 Q타입 생성된 것을 확인했습니다.plugins { id 'java' id 'org.springframework.boot' version '3.2.1' id 'io.spring.dependency-management' version '1.1.4' } group = 'study' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //test 롬복 사용 testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' //Querydsl 추가 implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" } tasks.named('test') { useJUnitPlatform() } clean { delete file('src/main/generated') } 테스트 코드package study.querydsl; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; import study.querydsl.entity.Hello; import study.querydsl.entity.QHello; import static org.assertj.core.api.Assertions.*; @Transactional @SpringBootTest class QuerydslApplicationTests { @Autowired EntityManager em; @Test void contextLoads() { Hello hello = new Hello(); em.persist(em); JPAQueryFactory query = new JPAQueryFactory(em); QHello qHello = new QHello("h"); Hello result = query.selectFrom(qHello) .fetchOne(); assertThat(result).isEqualTo(hello); } }해당 테스트 코드에서 em 부분에 컴파일 에러(Could not autowire. No beans of 'EntityManager' type found. )가 발생하고 테스트를 실행하면 아래와 같은 메세지가 출력됩니다.Execution failed for task ':test'. > There were failing tests. See the report at: file:///C:/Users/user/OneDrive/%EB%B0%94%ED%83%95%20%ED%99%94%EB%A9%B4/querydsl/build/reports/tests/test/index.html * Try: > Run with --scan to get full insights. Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. For more on this, please refer to https://docs.gradle.org/8.5/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. BUILD FAILED in 3s 4 actionable tasks: 3 executed, 1 up-to-date인텔리제이 종료 후 .idea 파일 삭제후 프로젝트 다시 실행해도 동일한 상황이어서 질문 드립니다. Gradle 버전은 8.5입니다.https://android-developer.tistory.com/entry/%ED%95%B4%EA%B2%B0-Deprecated-Gradle-features-were-used-in-this-build-making-it-incompatible-with-Gradle-80-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4해당 링크 방법도 해보았지만 동일한 상황입니다.
- 해결됨실전! Querydsl
강사님 Pageable->OrderSpecifier 변환 질문이 있습니다.
강의는 스프링 데이터 페이징 활용 3 - 컨트롤러 개발시간은 6:33코드는for (Sort.Order o : pageable.getSort()) { PathBuilder pathBuilder = new PathBuilder(member.getType(), member.getMetadata()); query.orderBy(new OrderSpecifier(o.isAscending() ? Order.ASC : Order.DESC,pathBuilder.get(o.getProperty()))); List<MemberTeamDto> content = query.fetch(); }루트 엔티티가 현재는 member 입니다. 직접 테스트해보고 싶어서 임의의 엔티티 user를 만들고 left join으로 묶었습니다@Override public Page<MemberTeamDto> searchPageComplex(MemberSearchCondition condition, Pageable pageable) { JPAQuery<MemberTeamDto> query = factory .select(new QMemberTeamDto( member.id, member.username, member.age, team.id, team.name, user.name)) .from(member) .leftJoin(member.team, team) .leftJoin(user).on(team.id.eq(user.id)) .where(usernameEq(condition.getUsername()), teamNameEq(condition.getTeamName()), ageGoe(condition.getAgeGoe()), ageLoe(condition.getAgeLoe())) .offset(pageable.getOffset()) .limit(pageable.getPageSize()); JPAQuery<Long> countQuery = factory .select(member.count()) .from(member) .leftJoin(member.team, team) .where(usernameEq(condition.getUsername()), teamNameEq(condition.getTeamName()), ageGoe(condition.getAgeGoe()), ageLoe(condition.getAgeLoe())); for (Sort.Order order : pageable.getSort()) { PathBuilder pathBuilder; if (order.getProperty().equals("name")) { pathBuilder = new PathBuilder<>(user.getType(), user.getMetadata()); } else { pathBuilder = new PathBuilder<>(member.getType(), member.getMetadata()); } query.orderBy(new OrderSpecifier(order.isAscending()? Order.ASC:Order.DESC,pathBuilder.get(order.getProperty()))); } List<MemberTeamDto> content = query.fetch(); return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchOne); }left join user를 추가하고 조건은 user.id = team.id 로 했습니다.http://localhost:8080/v2/members?page=0&size=3&sort=name,asc&sort=username,asc실행되는 SQL은select m1_0.member_id, m1_0.username, m1_0.age, m1_0.team_id, t1_0.name, u1_0.name from member m1_0 left join team t1_0 on t1_0.team_id=m1_0.team_id left join users u1_0 on m1_0.team_id=u1_0.id order by u1_0.name, m1_0.username limit 0,3;단순한 경우에는 상관이 없지만 조인하는 경우에는 동작을 잘 안한다고 설명을 해주셔서 간단하게 테스트를 해봤는데 동작을 하더라구요 강의 이후에 오류가 수정되어 해결이 된건지 아니면 제가 테스트를 잘못한걸까요?아니면 강사님께서 말씀하신 경우가 이 경우가 아닌 걸까요 ?
- 해결됨실전! Querydsl
querydsl Projection 성능 문제
안녕하세요 Querydsl Projection 을 활용해 DTO에 담는경우 성능 관련 질문이 있습니다. Querydsl에서 Projections.constructor를 활용해서 query를 작성하는경우 fetchJoin이 되지 않더라구요.일대 다 관계에서 fetchJoin을 하지 않게되면 n+1 이슈가 발생할거 같은데Projections을 활용하는 환경에서 성능개선은 어떻게 해야할까요?
- 해결됨실전! Querydsl
stringTemplate("...") 은 어떻게 찾으신건가요?
공식 문서 5.0.0 버전을 봐도 stringTemplate이나 function에 대한 소개가 없더라구요 이렇게 공식문서에서 찾을 수 없는 내용을 강사님께서는 어떻게 찾으시는지 궁금합니다.
- 미해결실전! Querydsl
BooleanBuilder 사용 방법에 대해서
private BooleanBuilder searchName(String name) { if (name == null || name.isBlank()) { return new BooleanBuilder(); } return new BooleanBuilder(QMember.member.username.eq(name)); } private BooleanBuilder searchAge(Integer age) { if (age == null) { return new BooleanBuilder(); } return new BooleanBuilder(QMember.member.age.eq(age)); } private BooleanBuilder allCond(String username, Integer age) { return searchName(username).or(searchAge(age)); } @DisplayName("BooleanBuilder 연속 사용") @Test void pr2(){ //given em.persist(new Member("둘리",15)); em.persist(new Member("또치",20)); em.flush(); em.clear(); QMember member = QMember.member; List<Member> findMember = queryFactory .select(member) .from(member) .where(searchName("name").and(searchAge(null)).and(searchAge(15))) .fetch(); System.out.println("findMember = " + findMember); }null 여부에 따라 Expression을 추가하거나 new BooleanBuilder를 반환하면and나 or일 경우 내부에서 합치거나 치환하는 방식을 통해 최종 BooleanBuilder를 사용할 수 잇더라구요public BooleanBuilder or(@Nullable Predicate right) { if (right != null) { if (predicate == null) { predicate = right; } else { predicate = ExpressionUtils.or(predicate, right); } } return this; }이렇게 사용하는 방법은 BooleanExpression을 사용하면 null 체크를 해야하는데따로 기존에 있는 메소드에서 null을 체크해야주기 때문에 좋을 거같은데단점은 매번 쿼리를 실행할 때마다 저 많은 조건문이 실행되니까 비효율적일까요 ?
- 미해결실전! Querydsl
paging2는 어떤식으로 수정해야되는 건가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)예[질문 내용]paging2에서 Deprecated된 fetchResults를 통해 전체 값 리밋값 옵셋 값 결과 개수 값을 다 구하는데 이제는 어떤식으로 해야되나요? 그냥 getTotal의 경우 count 를 통해 얻어올 수 있는데 나머지 값들은 어떻게 처리해야되나요?
- 미해결실전! Querydsl
gradle compileQuerydsl 안뜸
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]build.gradle에 작성을 했습니다.plugins { id 'java' id 'org.springframework.boot' version '3.2.0' id 'io.spring.dependency-management' version '1.1.4' } group = 'study' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //test 롬복 사용 testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' //Querydsl 추가 implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" } tasks.named('test') { useJUnitPlatform() } clean { delete file('src/main/generated') } GradlecompileQueryDsl이 존재하지 않습니다. 라이브러리로는 추가가 되어 있습니다어떻게 해결해야 할까요??
- 미해결실전! Querydsl
OrderRepository 변환
기존 jpashop에서 사용했던 MemberRepository는 querydsl을 사용하여 변환하는 과정을 강의를 보며 공부하였는데, OrderRepository에서 findAllByString와 findAllByCriteria를 querydsl을 이용하여 변환하는 강의는 어디를 보면 되나요??
- 미해결실전! Querydsl
RequestDto에서 요청값으로 받는 Enum에 조건식 또는 정렬 기준을 포함하는거에 대해서 어떻게 생각하시나요?
안녕하세요! 저는 7월부터 스타트업에서 JAVA기반으로 Spring과 Jpa를 활용하여 백엔드 개발자를 하고 있습니다! 다름이 아니라, 조회 로직에서 다양한 필터링 조건을 걸어야 하는 요구사항을 맡게 되었습니다. 이때 결론적으로 Enum의 필드로 조건식(BooleanExpression) 또는 정렬 조건(OrderSpecifier)를 가지고 있는걸 어떻게 생각하시는지 의견을 여쭙고 싶습니다!(제가 GPT에게 물어보았을 때는, 좋은 방법이나, Enum이 데이터 접근 계층에 의존적이게 된다는 단점을 지적받았습니다.)@Getter @RequiredArgsConstructor public enum ItemSortCriteria { ITEM_PRICE_ASC("상품 가격기준 오름차순 정렬", QItem.item.price.asc()), ITEM_PRICE_DESC("상품 가격기준 내림차순 정렬", QItem.item.price.desc()); private final String description; private final Orderspecifier orderSpecifier; } 제가 예전에 접했던 코드 중 하나라 문득 생각이 들었는데요,올바른 판단인지 / 아닌지 판단하기가 어려워서 질문 드립니다! 나아가 영한님 혹은 답변해주신 분들 께서는, 이렇게 든 생각이 올바른 판단인지 아닌지를 어떤 기준을 가지고 판단하시는지 그 사고의 흐름도 궁금합니다!
- 미해결실전! Querydsl
Library source does not match for class 에러
스프링 부트 3에서 작업 중입니다. 교안을 보고 build.gradle 설정했는데 유레카랑 오픈페인 의존성에 에러가 뜨더라구요.. 왜인지는 모르겠으나 구글링을 통해서 아래와 같이 설정했는데 이것과 관련이 있을까요? 구버전 query dsl이 심어진 건지,, 이 에러의 원인을 못 찾겠습니다.파일 설정을 src/main/아래로 둔 이유는 src파일 외에는 경로 설정을 따로해도 못 찾아서입니다 ㅜ
- 미해결실전! Querydsl
왜 getPage 할 때 람다식은 경고를 주는데, 더블콜론은 경고를 주지 않나요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]()->countQuery.fetchOne() 이나countQuery::fetchOne()나 똑같다고 생각했는데 아닌가요?
- 해결됨실전! Querydsl
@Transactional과 @PostConstruct를 나눈 이유
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]@PostConstruct나 @Transactional이나 둘 다 프록시인데,프록시는 보통 외부에서 호출을 하면 가로채서 먼저 프록시 메소드를 실행하고 넘겨주는데, 저거는 둘 다 프록시라 뭐를 해야할 지 몰라서? 프록시 메소드는 하나만 실행되서? 같이 쓰지 않는건가요?