월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨실전! Querydsl
order by 에 대한 궁금증이 있습니당
안녕하세용 예를 들어 [1, 3, 7, 2, 5] 이렇게 member id에 대한 list가 주어졌을떄 1, 3, 7, 2, 5 이 순서대로 member 엔티티리스트가 조회되도록 할수 있는 방법은 없는 건가요?
- 미해결실전! Querydsl
@OneToMany 에서 Cascade 되어있는데 foreign key로 연결되어 있는 테이블 삭제가 안됩니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]영상에서 12분 40초 부분에 bulkDelete와 관련된 내용입니다. 저는 일단 예제와는 조금 다르게 진행을 하였는데요. delete 하려는 User entity에는 OneToMany 관계로 되어있는 테이블이 하나 있습니다. 그래서 User entity에 Cascade All을 추가했는데 querydsl에서는 에러가 뜨면서 실행이 안되더라구요.제가알기로는 cascade를 설정해주면 entity가 삭제될 때 관련된 foreign key를 삭제해주는걸로 알고 있는데 아무리 찾아봐도 답이 안보여서 이렇게 질문남깁니다.
- 해결됨실전! Querydsl
페치 조인의 사용 기준이 고민됩니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요. 좋은 강의 잘 듣고 즐겁게 공부하고 있습니다.개인적으로 토이프로젝트를 하던 중에 쿼리 최적화(?) 기준에 관해서 고민이 생겼습니다. 현재 회원의 모든 게시물을 조회하는 로직이 있는데, 회원를 조회하고(1) 회원의 모든 게시물을 조회하고(2) 이렇게 총 2번의 쿼리가 발생합니다.이런 상황에 페치 조인을 통해 회원을 조회할 때 게시글도 한번에 페치 조인해오는 코드를 만드는 것이 더 효율적인지, 이정도는 괜찮은지 잘 결정하지 못하겠습니다. 해당 코드를 개발하더라도 사용하는 경우가 더 생길지 안생길지는 모르는 상황입니다.물론 정답은 없겠지만, 영한님의 의견을 들어보고 싶어서 질문 남깁니다! 좋은 강의 항상 감사합니다!+) 애초에 해당 접근방식의 문제가 아니여서 다르게 해결은 했습니다. 그래도 기준이 궁금하여 질문은 남겨두겠습니다. comment.getPost().getMember() 처럼 타고타고 들어가는 상황일 때마다 페치조인을 해주는 것이 가장 좋은지 궁금합니다!
- 미해결실전! Querydsl
Projections 질문 dto의 property와 entity의 property의 타입이 다를때 어떻게 변환을 할 수 있나요?
안녕하세요. 다음과 같이 Entity와 Dto가 LocalDateTime, OffsetDateTime 을 사용하여 데이타 타입이 다릅니다. 이경우에class EntityA { public Long id public LocalDateTime regDt; } class DtoA { public Long id public OffsetDateTime regDt; }querydsl 문장을 다음과 같이 하면, List<DtoA > list = jpaQueryFactory .select( Projections.fields( DtoA.class, entityA.id, entityA.regDt )) .from(entityA) .fetch() ; 다음과 같이 오류가 발생합니다.java.lang.IllegalArgumentException: java.time.LocalDateTime is not compatible with java.time.OffsetDateTime다음과 같은 변환함수를 쓰면 될거 같은데, public OffsetDateTime map(Date value) { try{ ZoneOffset zoneOffset = ZoneId.systemDefault().getRules().getOffset(Instant.now()); return value.toInstant().atOffset(zoneOffset); } catch( Exception e) { throw new RuntimeException( e ); } }이 함수를 querydsl에 어떻게 넣어야 할지 모르겠어요답변 부탁드립니다.감사합니다.
- 해결됨실전! Querydsl
PageableExecutionUtils 사용 시, count 쿼리 생략 조건
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]PageableExecutionUtils 을 사용시, count 쿼리 생략 조건에 "마지막 페이지 일 때" 라고 되어 있어서강의에 샘플 데이터 기반으로size=5, page=20 으로 마지막 페이지를 호출했는데,count 쿼리가 나가서 봤더니컨텐츠 사이즈가 0 이 아니면서 페이즈 사이즈 보다 작아야 되는 경우로 되어 있었습니다.해석하자면 카운트 쿼리 생략하는 경우가 "마지막 페이지이면서 컨텐츠 사이즈가 페이지 사이즈보다 작을 때" 인 것 같아서 의견드립니다.중복된 것이라면 죄송합니다
- 미해결실전! Querydsl
generated 파일
Q 가 생성이 안되네요 제 gradle 소스 코드입니다.plugins { id 'java' id 'org.springframework.boot' version '2.7.9' id 'io.spring.dependency-management' version '1.0.15.RELEASE' } group = 'study' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' // queryDSL 설정 implementation "com.querydsl:querydsl-jpa" implementation "com.querydsl:querydsl-core" implementation "com.querydsl:querydsl-collections" annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" // querydsl JPAAnnotationProcessor 사용 지정 annotationProcessor "jakarta.annotation:jakarta.annotation-api" // java.lang.NoClassDefFoundError (javax.annotation.Generated) 대응 코드 annotationProcessor "jakarta.persistence:jakarta.persistence-api" // java.lang.NoClassDefFoundError (javax.annotation.Entity) 대응 코드 runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() } // Querydsl 설정부 def generated = 'src/main/generated' // querydsl QClass 파일 생성 위치를 지정 tasks.withType(JavaCompile) { options.getGeneratedSourceOutputDirectory().set(file(generated)) } // java source set 에 querydsl QClass 위치 추가 sourceSets { main.java.srcDirs += [ generated ] } // gradle clean 시에 QClass 디렉토리 삭제 clean { delete file(generated) }
- 미해결실전! Querydsl
querydsl에서 oneToMany 관계인데 Many쪽 검색이 필요할 때 어떻게 해야하나요?
예를 들어 Order와 OrderItem이 있는데 Order의 검색을 동적쿼리로 검색해야해서 querydsl을 사용하고 있는 상황입니다. 그 중 검색조건이 OrderItem의 이름으로 검색해서 Order의 목록을 가져와야하는데 Order와 OrderItem을 조인하고 where절에 OrderItem의 이름으로 조회하는 방법 말고는 없을까요? 그럴 경우 distinct를 쓰거나 따로 중복 제거 로직을 넣어야해서ㅜ 혹시 다른 방법이 있나 문의드립니다.이런 경우에는 양방향 연관관계를 맺어주고 해결해도 될까요?
- 미해결실전! Querydsl
페이징 활용 1
pagable.getOffset이 없습니ㅏㄷ.
- 미해결실전! Querydsl
QueryDSL 에서 leftJoin & fetchJoin 후 lazy loading 이 되는 현상
영한님 안녕하세요, QueryDSL 공부 중 막히는 부분이 있어 질문드립니다.1:N 연관관계를 가지고 있는 두 엔티티 Team 과 Member 가 있을 때, QueryDSL 로 leftJoin & fetchJoin 으로 두 테이블을 조인하여 Member 목록을 조회하고 싶은데, 만약 Team 테이블에 FK 에 해당하는 row 가 존재하지 않는 경우에는 Member.team 에 그냥 null 이 들어있고 객체에 접근하더라도 추가적인 select 쿼리가 실행되지 않도록 하고 싶습니다. 그런데 제 바람과는 달리 Member.team 을 참조하는 시점에 lazy loading 이 되면서 select 쿼리가 실행되더라고요.실제 코드를 바탕으로 설명해보겠습니다.아래와 같이 1:N 연관 관계를 갖는 Team 과 Member 라는 엔티티가 있습니다.@Table(name = "member") @Entity class Member( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Int = 0, @Column(name = "team_id") var teamId: Long? = null, @Column(name = "name") var name: String? = null, @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "team_id", insertable = false, updatable = false, foreignKey = ForeignKey(name = "none")) val team: Team? = null, ) @Table(name = "team") @Entity class Team( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0, @Column(name = "name") var name: String? = null, )여기서 아래의 코드로 left outer join 쿼리를 실행합니다.val members = from(member) .leftJoin(member.team, team).fetchJoin() .fetch()DB 는 아래와 같이 데이터가 저장되어 있습니다.// team +----+-------+ | id | name | +----+-------+ | 1 | team1 | +----+-------+ // member +----+---------+------+ | id | team_id | name | +----+---------+------+ | 1 | 2 | John | +----+---------+------+그럼 저는 아래와 같은 Member 객체 하나로만 이루어진 List 를 얻을 수 있을 거라고 생각했고, team 변수에 접근할 때 select 쿼리 실행 없이 null 만을 반환할 것이라고 기대했습니다.{ "id": 1, "team_id": 2, "name": "John", "team": null }하지만 아래와같이 member 테이블을 lazy loading 하는 로그가 찍히네요.Hibernate: insert into team (id, name) values (default, ?) Hibernate: insert into member (id, name, team_id) values (default, ?, ?) Hibernate: select member0_.id as id1_7_0_, team1_.id as id1_9_1_, member0_.name as name2_7_0_, member0_.team_id as team_id3_7_0_, team1_.name as name2_9_1_ from member member0_ left outer join team team1_ on member0_.team_id=team1_.id Hibernate: select team0_.id as id1_9_0_, team0_.name as name2_9_0_ from team team0_ where team0_.id=?그런데 만약 DB 의 데이터 중 member 의 team_id 만 1로 변경하니 쿼리 후 member.team 에 접근하더라도 아래와 같이 lazy loading 하는 로그가 찍히지 않았습니다.Hibernate: insert into team (id, name) values (default, ?) Hibernate: insert into member (id, name, team_id) values (default, ?, ?) Hibernate: select member0_.id as id1_7_0_, team1_.id as id1_9_1_, member0_.name as name2_7_0_, member0_.team_id as team_id3_7_0_, team1_.name as name2_9_1_ from member member0_ left outer join team team1_ on member0_.team_id=team1_.id테스트에 사용한 코드는 아래와 같습니다.@DataJpaTest @Import(MemberService::class) // MemberService.listMembers() 에서 QueryDsl 로 쿼리를 합니다. class MyTest( private val sut: MemberService, private val em: EntityManager, ) : FunSpec( { beforeEach { val team = Team(name = "team1") em.persist(team) val member = Member( name = "John", teamId = team.id + 1, // 이것만 team.id 로 바꾸면 team 접근 시 select 로그가 찍히지 않습니다. ) em.persist(member) em.clear() } test("my test") { val members = sut.listMembers() members.shouldNotBeEmpty() val team = members.first().team println(team) } }, )어차피 조회한 엔티티에 변경을 가하지는 않을 것이라, Member 엔티티를 detach 시키고 team 에 접근하면 lazy loading 이 안될까 싶어서 해보았는데 여전히 lazy loading 이 되더라구요 ^^;일단 @QueryProjection 을 붙인 별도의 DTO 를 정의해 아래와같이 쿼리하는 식으로 해결하려고 하는데 더 좋은 방법은 없을까요?class MemberDto @QueryProjection constructor( val id: Int, val teamId: Long? = null, val name: String? = null, val teamName: String? = null, ) @Service @Transactional(readOnly = true) class MemberService : QuerydslRepositorySupport(Member::class.java) { private val member = QMember.member private val team = QTeam.team fun listMembers(): List<MemberDto> { val members = from(member) .select(QMemberDto(member.id, member.teamId, member.name, team.name)) .leftJoin(member.team, team) .fetch() return members } }감사합니다.
- 미해결실전! Querydsl
QueryDSL 5.0.0 기준으로 강의 내용을 정리했는데 올바르게 이해한 것일까요?
searchPageSimple(): 조회 쿼리와 카운트 쿼리를 한번에 실행searchPageComplex(): 조회 쿼리와 카운트 쿼리를 분리QueryDSL 5.0.0부터는 fetchResults()와 fetchCount()를 deprecated 메서드로 공지함에 따라, 강의 내용처럼 searchPageSimple()과 searchPageComplex()를 구분해서 구현할 필요 없이 searchPageComplex()의 방식으로만 구현하면 됨.@Override public Page<MemberTeamDto> searchWithPaging(MemberSearchCond cond, 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(cond.getUsername()), teamNameEq(cond.getTeamName()), ageGoe(cond.getAgeGoe()), ageLoe(cond.getAgeLoe()) ) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch(); // count 쿼리 (조건에 부합하는 로우의 총 개수를 얻는 것이기 때문에 페이징 미적용) Long total = queryFactory .select(member.count()) // SQL 상으로는 count(member.id)와 동일 .from(member) .leftJoin(member.team, team) .where( usernameEq(cond.getUsername()), teamNameEq(cond.getTeamName()), ageGoe(cond.getAgeGoe()), ageLoe(cond.getAgeLoe()) ) .fetchOne(); return new PageImpl<>(content, pageable, total); } 이 때, total을 아래와 같이 구할 수도 있지만long total = queryFactory .selectFrom(member) .leftJoin(member.team, team) .where( usernameEq(cond.getUsername()), teamNameEq(cond.getTeamName()), ageGoe(cond.getAgeGoe()), ageLoe(cond.getAgeLoe()) ) .fetch() // 조건에 부합하는 전체 데이터를 조회 (List) .size(); // List의 길이로 total을 구하기count 함수는 SQL 차원에서 지원하기 때문에 굳이 이렇게 전체 데이터를 받아온 뒤에 애플리케이션 레벨에서 별도로 size()를 호출해서 구할 필요 없고, 처음부터 카운트 쿼리를 호출하는 것이 나음.이유는 전체 데이터를 불러오고 나서 size()로 구하는 방식은 영속성 컨텍스트에 데이터를 전부 받아온 뒤에 개수를 따로 세는 것이기 때문에 불필요하게 메모리를 잡아먹기 때문. total을 구하는 방식에 대한 내용은 강의에 언급되지 않았기 때문에 제가 따로 검색해보고 내린 결론입니다. 제가 생각한 것이 맞는지 궁금합니다.이외에도 잘못된 부분이 있다면 지적해주시면 감사하겠습니다.
- 미해결실전! Querydsl
Projections.fields 관련 질문입니다.
Projections을 이용한 조회 테스트를 하고 있던중Projections.fields에 대해 궁금한점이 있습니다. Dto에 @AllArgsConstructor만 적용하고 Projections.fields를 사용하게 되면 해당 인스턴스를 만들지 못한다고 exception이 발생합니다.영한님께서 강의에서 말쓴하신 Projections.fields의 특성은 getter, setter가 필요가 없고 생성자 또한 필요가 없다라고 하셨는데 이상하게 @AllArgsConstructor를 추가하면 exception이 발생합니다.ex@Getter @AllArgsConstructor public class ArticleFieldsDto{ private Long id; private String title; private LocalDateTime lastModifiedDate; private Long lastModifiedBy; } 예외 로그com.querydsl.core.types.ExpressionException: com.mylaboratory.jpa_and_querydsl.projections.dto.ArticleFieldsDto at com.querydsl.core.types.QBean.newInstance(QBean.java:246) at com.querydsl.core.support.NumberConversions.newInstance(NumberConversions.java:86) at com.querydsl.jpa.FactoryExpressionTransformer.transformTuple(FactoryExpressionTransformer.java:51) at org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter.transformRow(RowTransformerTupleTransformerAdapter.java:30) at org.hibernate.sql.results.internal.StandardRowReader.readRow(StandardRowReader.java:109) at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:198) at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33) at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:443) at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:166) at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:91) at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31) at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:113) at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:335) at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:276) at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:571) at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:363) at org.hibernate.query.sqm.internal.QuerySqmImpl.list(QuerySqmImpl.java:1073) at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:457) at org.hibernate.query.sqm.internal.QuerySqmImpl.getSingleResult(QuerySqmImpl.java:1103) at com.querydsl.jpa.impl.AbstractJPAQuery.getSingleResult(AbstractJPAQuery.java:214) at com.querydsl.jpa.impl.AbstractJPAQuery.fetchOne(AbstractJPAQuery.java:326) at com.mylaboratory.jpa_and_querydsl.projections.ProjectionsTest.projections_field(ProjectionsTest.java:70) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727) at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) Caused by: java.lang.InstantiationException: com.mylaboratory.jpa_and_querydsl.projections.dto.ArticleFieldsDto at java.base/java.lang.Class.newInstance(Class.java:639) at com.querydsl.core.types.QBean.create(QBean.java:251) at com.querydsl.core.types.QBean.newInstance(QBean.java:222) ... 91 more Caused by: java.lang.NoSuchMethodException: com.mylaboratory.jpa_and_querydsl.projections.dto.ArticleFieldsDto.<init>() at java.base/java.lang.Class.getConstructor0(Class.java:3585) at java.base/java.lang.Class.newInstance(Class.java:626) ... 93 more 예외가 발생하지 않는 경우는 아래와 같습니다.@NoArgsConstructor, @AllArgsConstructor 모두 사용@NoArgsConstructor, @AllArgsConstructor 모두 사용 X@NoArgsConstructor 만 사용
- 미해결실전! Querydsl
UPDATE 동적쿼리 사용 질문
안녕하세요. 강의 듣고 미니 프로젝트 하며 궁금한 점이 생겨 질문드려봅니다. UPDATE문에서도 동적쿼리를 사용하고 싶어 정적쿼리를 아래와 같이 구현해보았는데 혹시 WHERE절의 BooleanExpression처럼 조금 더 깔끔하게 처리할 수 있는 방법이 있을지 문의드려봅니다. 감사합니다.
- 미해결실전! Querydsl
QueryDsl BooleanExpression에 대한 질문
[질문 내용]안녕하세요, QueryDsl 동적 쿼리 생성 코드 관련 선생님의 의견이 궁금합니다.BooleanExpression을 활용하여 동적 쿼리들의 조건을 생성하다보면 Entity, Column, 조건, 상황 별로 다양하고 많은 케이스들이 생겨 그만큼 코드 수를 많이 차지해 관리가 어려울 것이라 생각이 듭니다.그래서 reflection을 사용하여 아래와 같이 처리를 하면 어떨까 싶습니다.public class BooleanExpressionGenerator<T extends EntityPathBase> { private final T qEntity; public BooleanExpressionGenerator(T qEntity) { this.qEntity = qEntity; } public static <T extends EntityPathBase> BooleanExpressionGenerator<T> of(T QEntity) { return new BooleanExpressionGenerator(QEntity); } public <F extends ComparableExpressionBase> BooleanExpression createExpression(F filed, MethodName methodName, Object arg) throws Exception { Method method = filed.getClass().getMethod(methodName.name, arg.getClass()); return (BooleanExpression) method.invoke(qEntity, arg); } @Getter @RequiredArgsConstructor public enum MethodName { EQ("eq"), NE("ne"), GT("gt"), GTE("goe"), LT("lt"), LTE("loe"); private final String name; } } BooleanExpressionGenerator.of(book).createExpression(name, ComparableExpression.EQ, "자바 ORM 표준 JPA 프로그래밍");사실 질문 작성을 위해 작성하는데 5분정도 걸린 급조 된 코드인 점 먼저 말씀드립니다...!(실제 동작도 하지 않는 더티 코드)단지 이런 접근법에 대해서 선생님은 어떻게 생각하시는지가 궁금합니다.추가로 현재 선생님이 근무하시는 곳에서도 동적 쿼리 관련해서 BooleanExpression을 상당히 많이 활용할 것으로 보여지는데 어떤 식으로 관리하고 처리하는지도 궁금합니다!두서 없이 적은 점 양해부탁드립니다..!감사합니다.
- 미해결실전! Querydsl
서브쿼리 alias orderby 방법이 있나요 ?
안녕하세요 querydsl 코딩하다 막히는부분이 있어 질문글 남깁니다. return applyPagination(pageable, contentQuery -> contentQuery .selectDistinct(new QLocationDetailDto( member.idx.as("idx"), member.nickname.as("nickname"), member.memberImg.as("img"), ExpressionUtils.as( JPAExpressions.selectDistinct(qaComment.qa.idx.count()) .from(qaComment) .join(qaComment.qa, qa) .where(qaComment.member.eq(member)), "answerCount")) ) .from(member) .leftJoin(member.memberAddress, memberAddress) .leftJoin(member.qaComments, qaComment) .where( memberAddress.cityIdx.eq(cityIdx), member.grade.ne(QUIT), member.phoneNum.isNotNull(), memberEqualsRegion(regionIdx) ) .orderBy("answerCount").desc() );orderBy에 서브쿼리 이름명을 넣고싶은데 안되는거같아 문의드립니다 다른방법이 있을까요
- 미해결실전! Querydsl
join()를 작성하지 않아도 자동으로 join을 해주는데 join()을 써주는 이유
join()를 작성하지 않아도 자동으로 join을 해주는데 join()을 써주는 이유가 궁금합니다. @Test public void group() { List<Tuple> result = queryFactory .select(member.team.name, member.age.avg()) .from(member) // .join(member.team, team) .groupBy(member.team.name) .fetch(); Tuple teamA = result.get(0); Tuple teamB = result.get(1); assertThat(teamA.get(member.team.name)).isEqualTo("teamA"); assertThat(teamA.get(member.age.avg())).isEqualTo(15); //10, 20 assertThat(teamB.get(member.team.name)).isEqualTo("teamB"); assertThat(teamB.get(member.age.avg())).isEqualTo(35); //30, 40 }제가 위와 같이 코드를 수정하여 돌려봤는데 테스트를 잘 통과하였고 생성된 sql에서도 join을 자동으로 해주었습니다. 따로 join()을 쓰신 이유가 있을까요?
- 미해결실전! Querydsl
test
test할때는 log.info잘 사용 안하나요?
- 미해결실전! Querydsl
안녕하세요
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]1. start.spring.io 에 Querydsl 을 지원하지 않는 특별한 이유가 있는지 궁금합니다. 그리고 build.gradle 에서 Querydsl 설정이 잘 안된다면 임의로 QHello 파일을 생성하더라도 문제가 없는 것인지 궁금합니다.2. H2 DB 접근 시 localhost 로 변경해서 사용해야 하는 이유가 뭘까요?
- 미해결실전! Querydsl
3.0 querydsl
선생님이 올린 3.0 + querydsl로 다시 gradle했는데 Gradel -> other -> complieQuerydsl이 없는데 상관없는건가요?
- 미해결실전! Querydsl
중첩 객체 조회 관련
안녕하세요! querydsl 강의를 보고 실무에 적용 하던 중 중첩 객체에 대해서 한번의 join query로 만들 수 없을지 궁금하여 질문 드립니다. 만약, A -< B -< C (-< 은 one to many 를 의미) 관계를 가진 객체가 있다고 할 때selectFrom(A) .leftJoin(A.B) .leftJoin(A.B.C) .where(A.id.eq(1)) .fetch();위 코드의 반환 값이 아래와 같기를 희망 하는데요A = { id: 1, Bs: [ { id : 1, Cs : [ { id: 1 } ] } ] }oneToMany를 조인 하게 되면, SQL은 many의 row를 반환하게 되면서, A객체가 B의 갯수만큼 반환 되게 됩니다.group by등을 통해 해결 하려 했을 때는, oneToMany 컬렉션들이 모두 불러와지지 않는것을 확인 하였고, group by를 활용 하지 않고, 모든 row를 불러와서 aggregate하는 방식으로 코드를 구현 했습니다. 매번 쿼리문을 작성할 때 마다 aggregate하는 코드를 작성하는 것은 옳지 않을 것 같아, 혹시 더 나은 방법이 있을지 문의 드립니다. 혹시 중첩 쿼리를 join 으로 모두 찾아 객체에서 맵핑하려는 시도가 bad practice라면 쿼리 숫자가 늘어나더라도, findByAId, findByBId 등의 방식으로 여러번 쿼리를 하고, 중간에 캐시 레이어를 두는것이 더 나을지도 궁금 합니다. 항상 좋은 강의 감사합니다 :)
- 미해결실전! Querydsl
스프링 부트 3.0 + Querydsl 설정 관련
안녕하세요! 강의 잘 듣고 있습니다 감사합니다.강의를 따라가다가 잘 안되는 부분이 있어서 질문글 하나 남겨봅니다.Gradle -> Tasks -> build -> cleanGradle -> Tasks -> other -> compileQuerydsl실행 시에 정상적으로 Q타입 클래스가 생성이 됩니다.그런데 이후에 테스트 코드를 돌려보면이런 오류가 뜹니다.이것저것 해보다가 build파일이 없는 상태에서(삭제 후에) 테스트를 돌리면 돌아가긴 합니다.정상적으로 빌드해서 돌려보고 싶은데 설정을 어떻게 바꿔야 할까요?https://drive.google.com/file/d/1H7Sz9Z994odDceIhuTp9S4bpfvhDjxAr/view?usp=sharing구글 드라이브 링크입니다.