월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! Querydsl
on()구문 질문입니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]아래의 두 코드는 방식의 차이일뿐 같다라고 봐도 무방할까요?- 연관관계가 있는 경우from(member).join(member.team, team)- 연관관계가 없는 경우from(member).join(team).on(member.team.id.eq(team.id))
- 미해결실전! Querydsl
Querydsl 버전 관련
안녕하세요! Querydsl 을 공부한 후 현재 인턴으로 있는 회사에서 프로젝트에 적용해보려고 합니다. 근데 해당 프로젝트의 스프링 버전이 2.2.0 release 버전인데 해당 버전에서 Querydsl은 어떻게 해야하는지 여쭤볼 수 있을까요 ?
- 미해결실전! Querydsl
정렬 조건에 대해 질문이 있습니다.
public enum Tier { CHALLENGER("challenger"), GRANDMASTER("grandmaster"), MASTER("master"), DIAMOND("diamond"), EMERALD("emerald"), PLATINUM("platinum"), GOLD("gold"), SILVER("silver"), BRONZE("bronze"), IRON("iron"), NULL("null"); private final String tier; Tier(String tier) { this.tier = tier; } }이런 enum을 필드로 가지고 있는 entity가 있습니다.public class MyEntity { ... @NotNull @Column(name = "queue", columnDefinition = "VARCHAR(20)") @Enumerated(EnumType.STRING) private Tier queue; ... } 그런데 querydsl로 이 enum기준으로 custom sort를 할 경우에는 어떻게 해야하나요?예를 들면 enum Tier에 적혀있는 순서대로 CHALLENGER > GRANDMASTER > ... > NULL 순서대로 정렬할 때 어떻게 해야하는지 궁금합니다!
- 미해결실전! Querydsl
QuerydslApplicationTests 오류
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not prepare statement Caused by: org.hibernate.exception.SQLGrammarException: could not prepare statement Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Sequence "HIBERNATE_SEQUENCE" not found; SQL statement:call next value for hibernate_sequence [90036-199] h2는 1.4.199 사용중이며 application.yml파일도 똑같이 했는데 계속 저런 오류가 뜹니다..
- 미해결실전! Querydsl
어그리게이트간 id 참조를 할 때는 querydsl 어떻게 잘 활용할 수 있을까요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]https://www.popit.kr/id%EB%A1%9C-%EB%8B%A4%EB%A5%B8-%EC%95%A0%EA%B7%B8%EB%A6%AC%EA%B2%8C%EC%9E%87%EC%9D%84-%EC%B0%B8%EC%A1%B0%ED%95%98%EB%9D%BC/이 글을 보고 다른 어그리게이트 간에는 id 참조를 한다고 하면querydsl 을 통해서 다른 어그리게이트간 join 은 어떻게 활용할 수 있나요?예를 들어서 Order, Review 라는 도메인이 아래와 같다고 해볼게요. @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Review { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String content; @Column private int rate; private Long orderId; public Review(final String content, final int rate) { this.content = content; this.rate = rate; } }@Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String name; @Column private String orderStatus; @Column private LocalDateTime createdAt; public Order(final String name, final String orderStatus) { this.name = name; this.orderStatus = orderStatus; this.createdAt = LocalDateTime.now(); } } 이때 생성되는 QType 에는 두 엔티티간의 참조 관계를 표현할 수 없는데 이런 경우에는 join 등을 어떻게 활용할 수 있을까요제가 "어그리게이트간 id 참조를 해라!" 잘못 이해하고 있는 것일까요?
- 미해결실전! Querydsl
inner join 인 경우 join 문이 없어도 되는 경우
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)예[질문 내용]queryDsl 강의 중 조인편을 보면서 한가지 실험을 해봤습니다.@Test void 팀A에_소속된_모든_멤버를_조회힌다() { List<Member> found = jpaQueryFactory.selectFrom(member) .where(member.team.name.eq("teamA")) .fetch(); assertThat(found) .map(Member::getTeam) .extracting("name") .allMatch(teamName -> teamName.equals("teamA")); } @Test void 조인을_통해_팀A에_소속된_모든_멤버를_조회힌다() { List<Member> found = jpaQueryFactory.selectFrom(member) .join(member.team, team) .where(team.name.eq("teamA")) .fetch(); assertThat(found) .map(Member::getTeam) .extracting("name") .allMatch(teamName -> teamName.equals("teamA")); }첫번째 테스트는 join 문 없이 QType 을 활용해서 where에 필요한 조건을 작성하였구요두번째 테스트는 join 메서드를 활용한 것 입니다.테스트 결과도 같고 실행 후 실제 수행된 쿼리도 동일하더라구요이런 경우에는 어떤 방법이 더 적절할까요?
- 미해결실전! Querydsl
QueryDSL내부 동작관련 질문입니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 직접적인 관련은 없습니다2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]QueryDSL은 내부적으로 JPQL을 사용해서 DB와 통신을 하느건가요?
- 미해결실전! Querydsl
contextLoad에 작성하신 테스트 관련 질문입니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]현재 본 강의까지 H2설정을 application.yml에 하지 않았는데 contextLoads()에 작성한 테스트가 어떻게 성공적으로 수행되는 건가요?
- 미해결실전! Querydsl
JPQL vs QueryDSL
JPQL 보다 QueryDSL 사용하는게 좀더 오류를 빨리 잡을 수 있어서 QueryDSL을 사용하는게 더 좋을 것 같은데, QueryDSL 보다 JPQL이 유용한 경우가 있을까요?
- 해결됨실전! Querydsl
PageableExecutionUtils.getPage 의 최적화 로직만 따로 뺀 count 메소드입니다.
갱신된 강의자료에도 나와 있듯이, fetchResult, fetchCount 등의 메소드는 deprecated 예정입니다. 또한 해당 메소드는 Page 타입을 반환하기 때문에 Page 타입을 직접적으로 조작해야 한다는 제약이 있습니다. 이걸 잘 쓰면 되는데, Page 의 시작번호 등 제약도 있어서 저는 회사에서 Page 를 따로 만들어서 사용하거든요. 그래서 search 메소드와 count 메소드는 항상 분리하고 있습니다.2. 그런 점에서 count 만 최적화하는 로직만 베껴서 만든 최적화 메소드입니다.실제로 count 구문을 실행하기 위한 메소드입니다. 필요에 따라서 public 으로 만들어도 될 것 같네요. // count 실행 메소드 private Long countByCond(MemberSearchCond cond) { return query .select(member.countDistinct()) .from(member) .where( usernameEq(cond.getUsername()), teamNameEq(cond.getTeamName()), ageGoe(cond.getAgeGoe()), ageLoe(cond.getAgeLoe()) ) .fetchOne(); } 최적화 로직을 베낀 메소드입니다. 스프링 데이터 JPA 는 아래 코드와 같이 page, size 값이 null 이 아니고, 적절한 범위에 있는지를 판단하여 isPaged 라는 분기를 만듭니다. 참고로 코드를 분석하면서 내린 뇌피셜이니 혹시 틀리다면 말씀해주세요. page 가 0 이 아니라 1 부터 시작하는 건 제 취향입니다. 회사에서 그렇게 쓰고 있거든요. 필요에 따라 0 부터 시작하도록 바꾸는 건 어렵지 않을 것 같습니다.public Long countByCondOptimization(List<?> content, MemberSearchCond cond, Long page, Long size) { boolean isPaged = page != null && size != null && page > 0 && size > 0; long offset = isPaged ? (page - 1) * size : 0L; long contentSize = content.size(); if (!isPaged || offset == 0) { if (!isPaged || size > contentSize) { return contentSize; } return this.countByCond(cond); } if (contentSize != 0 && size > contentSize) { return offset + contentSize; } return this.countByCond(cond); } 이렇게 하여 count 쿼리를 리스트 조회 쿼리와 분리하여 재사용성을 높이면서, 성능도 최적화할 수 있습니다.감사합니다.
- 해결됨실전! Querydsl
P6Spy 포맷 설정 공유합니다.
jpa 로그의 포맷처럼 줄바꿈을 넣으면서, 동시에 ? 자리에 바인딩 파라미터를 넣는 코드입니다. P6Spy 1.8.1, Spring Boot 2.7.x, 마리아DB 10.1.x 사용했습니다.application.properties 에서 JDBC 드라이버나 URL 에 P6Spy 를 추가하면 로그가 2번 출력될 수 있으니 주의하세요. 아래처럼 P6Spy 관련 드라이버? 코드? 가 포함되지 않도록 하시면 됩니다.# datasource spring.datasource.url=jdbc:mariadb://localhost:3306/YOUR_SCHEMA spring.datasource.username=YOUR_USERNAME spring.datasource.password=YOUR_PASSWORD # p6spy log logging.level.p6spy=info decorator.datasource.p6spy.enable-logging=true 로그의 포맷을 실질적으로 꾸미는 구현 클래스입니다. 추가 정보는 실행시간 제외하고는 뺐는데, 필요하시면 추가하시면 됩니다. import com.p6spy.engine.logging.Category; import com.p6spy.engine.spy.appender.MessageFormattingStrategy; import org.hibernate.engine.jdbc.internal.FormatStyle; import java.util.Locale; public class P6SpyFormatter implements MessageFormattingStrategy { private static final String NEW_LINE = "\n"; private static final String TAP = "\t"; private static final String CREATE = "create"; private static final String ALTER = "alter"; private static final String DROP = "drop"; private static final String COMMENT = "comment"; @Override public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) { if (sql.trim().isEmpty()) { return formatByCommand(category); } return formatBySql(sql, category) + getAdditionalMessages(elapsed); } private static String formatByCommand(String category) { return NEW_LINE + "Execute Command : " + NEW_LINE + NEW_LINE + TAP + category + NEW_LINE + NEW_LINE + "----------------------------------------------------------------------------------------------------"; } private String formatBySql(String sql, String category) { if (isStatementDDL(sql, category)) { return NEW_LINE + "Execute DDL : " + NEW_LINE + FormatStyle.DDL .getFormatter() .format(sql); } return NEW_LINE + "Execute DML : " + NEW_LINE + FormatStyle.BASIC .getFormatter() .format(sql); } private String getAdditionalMessages(long elapsed) { return NEW_LINE + NEW_LINE + String.format("Execution Time: %s ms", elapsed) + NEW_LINE + "----------------------------------------------------------------------------------------------------"; } private boolean isStatementDDL(String sql, String category) { return isStatement(category) && isDDL(sql.trim().toLowerCase(Locale.ROOT)); } private boolean isStatement(String category) { return Category.STATEMENT.getName().equals(category); } private boolean isDDL(String lowerSql) { return lowerSql.startsWith(CREATE) || lowerSql.startsWith(ALTER) || lowerSql.startsWith(DROP) || lowerSql.startsWith(COMMENT); } } 5. 아래 코드가 중요한데, 위 4에서 만든 포맷을 적용하는 시점을 알려주기 위해 만드는 JDBC 이벤트 리스너입니다. 어떤 블로그나 포럼에서는 포맷 적용 시점을 @PostConstruct 로 하던데, 그렇게 하면 테이블 create, drop 시점에 적용이 안 돼서 그렇게 하면 안 되고, 아래와 같이 Connection 이 생성되자마자 적용하면 됩니다. import com.p6spy.engine.common.ConnectionInformation; import com.p6spy.engine.event.JdbcEventListener; import com.p6spy.engine.spy.P6SpyOptions; import java.sql.SQLException; public class P6SpyEventListener extends JdbcEventListener { @Override public void onAfterGetConnection(ConnectionInformation connectionInformation, SQLException e) { P6SpyOptions.getActiveInstance().setLogMessageFormat(P6SpyFormatter.class.getName()); } } 이렇게 2개의 구현 클래스를 만들었으면, 아래와 같이 Bean 으로 등록해주기만 하면 설정 끝입니다. import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class P6SpyConfig { @Bean public P6SpyEventListener p6SpyCustomEventListener() { return new P6SpyEventListener(); } @Bean public P6SpyFormatter p6SpyCustomFormatter() { return new P6SpyFormatter(); } }
- 해결됨실전! Querydsl
동적으로 Order 절 만드는 코드 공유합니다
강의에서는 Query DSL 4.x 버전이어서 제네릭 없는 예제 코드인 것 같은데, 제가 올리는 버전은 5.0 버전이어서 차이가 있음을 감안해주세요.정렬 조건을 하나만 추가하는 코드입니다. 정렬 조건을 여러 개 추가하려면 반복문을 돌면서 JPAQuery 를 동적으로 확장해나가면 됩니다. // 페이징하는 메소드에서 사용 private Expression<? extends Comparable<?>> specifyMemberProperty(String prop) { prop = prop == null ? "" : prop.toLowerCase(); if (prop.equals("username")) { return member.username; } if (prop.equals("age")) { return member.age; } return member.id; } // 페이징하는 메소드 // ... .orderBy(new OrderSpecifier<>("desc".equalsIgnoreCase(dir) ? Order.DESC : Order.ASC, specifyMemberProperty(prop))) .fetch(); --저는 일단 이렇게 만들어봤는데, 다른 분께서 더 나은 코드, 더 빠른 코드가 있다면 저한테도 알려주세요.감사합니다.
- 미해결실전! Querydsl
동적 쿼리
Where 절에서 동적 쿼리를 작성할 수 있듯이, orderBy 절에서도 동적쿼리를 작성해도 괜찮나요 ?근데 orderBy 절은 null이 되면 안될 것 같은데 이런 경우에 동적으로 어떻게 해야하는지 궁금합니다. 또 실무에서는 where절과 order절 모두 동적 쿼리를 자주 사용하는지 궁금합니다
- 미해결실전! Querydsl
countQuery 최적화 질문
countQuery관련해서 궁금한 것이 있습니다.@Override public Page<ReportChangeKRWDto> search(ReportSearchRequestDto dto, Pageable pageable) { List<ReportChangeKRWDto> content = queryFactory .select(new QReportChangeKRWDto( reportChange.id.intValue(), //번호는 일단 임의로 reportChange.referenceDate, reportChange.changeAmount, reportChange.beforeAsset, reportChange.changeRatio, reportChange.afterAsset) ) .where(searchType(dto)) .from(reportChange) .orderBy(sortCondition(dto)) .offset(pageable.getOffset()) .limit(10) //TOP 10 고정 .fetch(); //countQuery 따로 JPAQuery<Long> countQuery = queryFactory .select(reportChange.count()) .from(reportChange) .where(searchType(dto)) .orderBy(sortCondition(dto)); // .offset(pageable.getOffset()) // .limit(10); return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchOne); }여기서 countQuery를 통해 최적화 하고 싶다면 countQuery부분에는 offset, limit을 빼고 쿼리?부분들만 적용해야 하는건가요 ??
- 해결됨실전! Querydsl
영속성 콘텍스트의 범위.
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요.영속성콘텍스트에 영속화된 Entity 로 생각이 드는데도 불구하고 영속성 콘텍스트가 아니고 쿼리의 호출결과로 데이터를 얻어오는 부분이 있어서 질문을 드립니다.테스트 코드는 아래와 같습니다.참고: boardId = boardEntity @Id@Transactional public BoardDto updateBoard(Integer boardId, String title) { jBoardEntity entity = jpaQueryFactory.selectFrom(boardEntity).where(boardEntity.baordId.eq(boardId)).fetchOne(); entity.updateTitle(title); entityManagerFactory.getPersistenceUnitUtil().isLoaded(entity) // true return jpaQueryFactory.selectFrom(boardEntity).where(boardEntity.baordId.eq(boardId)).fetchOne(); }에서 처음 selectFrom 때 select 쿼리후 entity 정상반환하여 영속회되고 update title 문까지 정상동작합니다.이후 영속성 콘텍스트에 로드가 됐다는걸 확인해보았고 동일한 ID 의 entity 를 조회했을때는 영속성 컨텍스트에서 제공되길 기대했으나 console 로그에는 sql 이 나가는 것으로 보아 실제 db 에 sql 이 작동한것으로 보입니다.혹시 제가 놓친 부분이있다면 말씀해주시면 감사하겠습니다.
- 해결됨실전! Querydsl
Querydsl 배포시 질문입니다.
plugins { id 'java' id 'org.springframework.boot' version '3.0.2' id 'io.spring.dependency-management' version '1.1.0' id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" } //querydsl 추가 시작 def querydslDir = "$buildDir/generated/querydsl" querydsl { jpa = true querydslSourcesDir = querydslDir } sourceSets { main.java.srcDir querydslDir } compileQuerydsl{ options.annotationProcessorPath = configurations.querydsl } configurations { compileOnly { extendsFrom annotationProcessor } querydsl.extendsFrom compileClasspath } //querydsl 추가 끝 강의 들을 때는 아래와 같이 Gradle에 q파일 위치를 설정을 해 주었는데요이대로 배포를 진행하게 되면 실제 배포 단계에서는 문제가 발생합니다. 따라서 아래 링크를 찾아서 확인해 보았는데 이 경우는 배포가 문제 없이 잘 되었습니다https://www.inflearn.com/questions/787440/querydsl-gradle-%EC%B6%94%EA%B0%80%ED%9B%84-%EB%8D%94%EB%B8%94%ED%81%B4%EB%A6%AD%ED%95%98%EC%97%AC-%EC%8B%A4%ED%96%89%ED%95%A0%EB%95%8C-%EC%98%A4%EB%A5%98.아래는 배포 문제없이 진행된 gradle 입니다. plugins { id 'java' id 'org.springframework.boot' version '3.0.2' id 'io.spring.dependency-management' version '1.1.0' } 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.5.6' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //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') } 확인을 해 보면 QueryDsl 플러그인이 지워져 있고, q파일이 빌드 되는 위치를 따로 지정하지 않는 것 같습니다. 이렇게 할 경우 배포는 가능하지만 CompileQuerydsl 을 찾을 수가 없어서 Q파일 생성이 불가능 합니다.개발 시의 Gradle과 배포시 Gradle을 다르게 가져가는 것 말고는 방법이 없을까요?
- 미해결실전! Querydsl
현재 fetchResults(), fetchCount() deprecated
그렇다면 코드를 어떻게 짜야하나요 ? 내용과 카운트 쿼리 따로 해야하는 것은 이해했는데 따로 하려면 이제 어떻게 짜야하나요 ?
- 해결됨실전! Querydsl
@QueryProjection 사용시 집합함수는 불가능한가요?
.select(new QDto(point.p.sum())) .from(point) 이런식으로 할려는데 dto에 integer로 했는데 안되네요집합함수같은거는 dto로 바로 반환 불가능한가요
- 미해결실전! Querydsl
인텔리제이 Build 설정과 Q클래스
// querydsl 추가 implementation 'com.querydsl:querydsl-core' implementation 'com.querydsl:querydsl-jpa' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" annotationProcessor 'jakarta.persistence:jakarta.persistence-api' annotationProcessor 'jakarta.annotation:jakarta.annotation-api'위처럼 build.gradle 설정을 조금 다르게 했습니다.그런데 Build and run using을 Intellij IDEA로 설정하면 Q클래스 파일이 생성되긴하는데 사용하려고 하면 import가 되지 않고, Build and run using을 Gradle로 설정하면 정상적으로 import가 되는데 설정 문제로 그러는걸까요? 이유가 궁금합니다.
- 미해결실전! Querydsl
from절(QTeam.team)과 QMember.member차치
강의 7분16초에서List<Tuple> result = queryFactory .select(QTeam.team.name, QMember.member.age.avg()).from(QMember.member).join(QMember.member.team, QTeam.team).groupBy(QTeam.team.name).fetch();위 코드로 하면 성공하지만List<Tuple> result = queryFactory .select(QTeam.team.name, QMember.member.age.avg()).from(QTeam.team).join(QMember.member.team, QTeam.team).groupBy(QTeam.team.name).fetch();이렇게 코드를 작성하면 맨아래와 같은 에러가 발생합니다.하지만 제가 H2에서 위 코드를 SQL로 바꾸면 아래와 같이 된다고 생각해서select t.NAME, AVG(m.AGE) from Team t join Member m on m.TEAM_ID=t.ID group by t.NAME;이렇게 적어서 실행해보니원하는 결과대로 잘 나오긴하는데 왜 Querydsl에서는 이러한 에러가 발생하는지 궁금합니다.========================================org.hibernate.hql.internal.ast.InvalidPathException: Invalid path: 'member1.team' at org.hibernate.hql.internal.ast.util.LiteralProcessor.lookupConstant(LiteralProcessor.java:111) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.ast.tree.DotNode.resolve(DotNode.java:218) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:114) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:109) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromJoinElement(HqlSqlWalker.java:411) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.joinElement(HqlSqlBaseWalker.java:4007) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3793) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3671) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:746) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:602) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:339) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:287) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:636) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:748) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:114) ~[hibernate-core-5.6.10.Final.jar:5.6.10.Final] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311) ~[spring-orm-5.3.22.jar:5.3.22] at com.sun.proxy.$Proxy113.createQuery(Unknown Source) ~[na:na] at com.querydsl.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:132) ~[querydsl-jpa-5.0.0.jar:na] at com.querydsl.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:125) ~[querydsl-jpa-5.0.0.jar:na] at com.querydsl.jpa.impl.AbstractJPAQuery.fetch(AbstractJPAQuery.java:242) ~[querydsl-jpa-5.0.0.jar:na] at study.querydsl.QuerydslbasicTest.group(QuerydslbasicTest.java:215) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725) ~[junit-platform-commons-1.8.2.jar:1.8.2] at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66) ~[junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.8.2.jar:1.8.2] at java.base/java.util.ArrayList.forEach(ArrayList.java:1541) ~[na:na] at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.8.2.jar:1.8.2] at java.base/java.util.ArrayList.forEach(ArrayList.java:1541) ~[na:na]