월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! Querydsl
No default constructor found;
안녕하세요!김영한 강사님의 강의를 들으며 제 프로젝트에 맞춰서 강사님 코드를 클론 코딩해서 공부를 하던 중 하단과 같은 오류가 떠서 문의드립니다. Error creating bean with name 'likeApiController' defined in file [/Users/gimnayeon/Desktop/GreenProject/GrinGreen/out/production/classes/com/grin/GrinGreen/api/LikeApiController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'likeService' defined in file [/Users/gimnayeon/Desktop/GreenProject/GrinGreen/out/production/classes/com/grin/GrinGreen/service/LikeService.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'businessRepository' defined in file [/Users/gimnayeon/Desktop/GreenProject/GrinGreen/out/production/classes/com/grin/GrinGreen/repository/BusinessRepository.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.grin.GrinGreen.repository.BusinessRepository]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.grin.GrinGreen.repository.BusinessRepository.<init>() 오류 그대로 기본 생성자가 없다는 거 같은데 제가 아직 부족해서 그런지 아무리 찾아봐도 어디서 문제인지 모르겠어서요.. 도움 부탁드립니다.. 저는 멤버 가입 후 그 멤버로 업체를 만들어서 업체 목록을 조회를 하려고 했습니다!BusinessSearchCondition@Data public class BusinessSearchCondition { private String businessName; }BusinessDto@Data public class BusinessDto { private Long business_id; private String businessName; @QueryProjection public BusinessDto(Long business_id, String businessName) { this.business_id = business_id; this.businessName = businessName; } }InitBusiness@Profile("local") @Component @RequiredArgsConstructor public class InitBusiness { private final InitBusinessService initBusinessService; @PostConstruct public void init() { initBusinessService.init(); } @Component static class InitBusinessService { @PersistenceContext EntityManager em; private final MemberService memberService; private final BusinessService businessService; InitBusinessService(MemberService memberService, BusinessService businessService) { this.memberService = memberService; this.businessService = businessService; } @Transactional public void init() { Member member = new Member(); member.setNickname("test"); member.setMail("test@test.com"); member.setPassword("test1234!"); member.setMember_type("B"); member.setMember_status("J"); member.setHint_password("hint_01"); member.setAnswer_password("answer"); member.setUpdated_at(now()); member.setCreated_at(now()); String memberJoin = memberService.join(member); for (int i = 0; i < 100; i++) { Business business = new Business(); business.setBusinessName("테스트밥집"+i); business.setHomepage("test" + i + ".com"); business.setPhone("010-1234-5678"); business.setAddress("제주특별자치도 제주시 첨단로 242"); business.setLng((float) 33.450701); business.setLat((float) 126.570667); business.setCreated_at(now()); business.setUpdated_at(now()); business.setMember(member); String businessJoin = businessService.join(business); } } } }MemberService@Transactional public String join(Member member){ //비밀번호 암호화 후 레포지토리에 넘기기 String encodedPassword = passwordEncoder.encode(member.getPassword()); member.setPassword(encodedPassword); validateDuplicateMember(member);//중복회원검증 memberRepository.save(member); return member.getMail(); }BusinessService/** 업체생성 **/ @Transactional public String join(Business business){ validateDuplicateBusiness(business);//중복회원검증 log.info("business {}", business); businessRepository.save(business); return business.getBusinessName(); }BusinessRepository@Repository @RequiredArgsConstructor public class BusinessRepository { private final EntityManager em; private final JPAQueryFactory queryFactory; public BusinessRepository(EntityManager em) { this.em = em; this.queryFactory = new JPAQueryFactory(em); } public List<BusinessDto> search(BusinessSearchCondition condition){ return queryFactory .select(new QBusinessDto( business.id, business.businessName)) .from(business) .where(businessNameEq(condition.getBusinessName())) .fetch(); } private BooleanExpression businessNameEq(String businessName) { return isEmpty(businessName) ? null : business.businessName.eq(businessName); } }
- 해결됨실전! Querydsl
DTO는 목적마다 여러개 생성해서 사용하는건가요?
안녕하세요! 강의 너무 잘 듣고있습니다.다름이 아니라, DTO관련해서 의문점이 하나 생겨서 문의드립니다.API Controller에서 요청 데이터를 받는 것도 DTO, 응답 데이터를 전달해주는 것도 DTO를 사용하라고 하셨는데, 데이터 조회에도 DTO를 사용하는 경우가 많다고 하셨습니다.그럼 DTO를 목적마다 다 생성해서 사용하는 것이 좋은 설계인건가요?? 아니면, 이용하는 필드가 같은 경우,~ 예를 들어 "DB조회에 이름, 나이 조회" & "요청 데이터에 이름, 나이 입력" 인경우 ~에는 DTO를 공용으로 사용하는걸까요? DTO를 언제, 어떻게 만들어서 사용해야 할지 잘 감이 안옵니다 ㅠㅠ
- 미해결실전! Querydsl
안녕하세요 김영한 강사님 질문이 있습니다.
이번 강의에서 배운 서브 쿼리에서 subQuery() JPAExpressions를 사용하셨는데, JPAExpressions 대신에 queryFactory를 사용해도 테스트는 통과가 되는데, 서브쿼리를 사용할 때 JPAExpressions를 사용하라고 말씀해주신 이유가 궁금합니다.
- 미해결실전! Querydsl
Querydsl4RepositorySupport에 @Repository와 @Autowired
안녕하세요. 강의 잘 보고 있습니다.궁금한 점이 있습니다.Querydsl4RepositorySupport는 abstract class인데 왜 @Repository를 붙이는건가요? 실체 구체화할 부모 클래스에 @Repository를 붙이면 되는것 아닌가요? Querydsl4RepositorySupport는 abstract class라 객체로 생성이 안되는데 빈으로 등록이 가능한가요?이어서 setEntityManager에 @Autowired를 붙임으로써 의존성을 주입하고 있습니다. 그때에 entityManager라는 빈을 등록해주겠죠. 그런데 setEntityManager는 언제, 누가 호출하게 되는건가요?
- 미해결실전! Querydsl
코드도 공유해주실 수 있으신가요?
학습하는데 실행이 안되는 부분도 있고, 실무에 쓰기 위해 실전 강의 모두 결제하고 속성으로 듣고 있습니다.다른 실전 강좌들 처럼 코드를 zip파일로 공유해주실 수 있으신가요?
- 미해결실전! Querydsl
쿼리에 대해 고민이 있습니다.
아직 현업을 겪어보지 못한 취준생입니다.강의를 보고 공부를 하던 중 querydsl을 이용해 dto에 fit한 쿼리를 한번에 나오게끔 어찌저찌 짜봤는데요.공부를 하다 궁금한 점이 생겨서 질문 드립니다.로직을 위해 한 3번 정도의 쿼리가 나간 뒤 자바 코드로 로직에 맞게 수정하는 것과,로직을 위해 한번의 쿼리가 나가면서 쿼리가 복잡해지는 것 중 어느게 좋은 쿼리일까요?제 생각에는 3번의 가독성 좋은 쿼리가 나가는 것이 좋을 것 같습니다.혹시 현업에서는 아니면 저보다 선배님들은 어떤 식으로 하시는지 궁금합니다.
- 미해결실전! Querydsl
search Test 관련 - JPAQueryFactory와 EntityManager
안녕하세요 강의 항상 잘 보고 있습니다.몇가지 궁금한 점이 있어서 질문 드립니다!public static void main(String[] args) { SpringApplication.run(QuerydslApplication.class, args); } @Bean JPAQueryFactory jpaQueryFactory(EntityManager em){ return new JPAQueryFactory(em); }이전 MemberJpaRepository에서 보여주셨던 것과 같이 시작 메소드에서 em을 주입받은 queryFactory를 Bean으로 등록하고,private final JPAQueryFactory queryFactory; public MemberRepositoryImpl(JPAQueryFactory queryFactory){ this.queryFactory = queryFactory; }MemberRepositoryImpl에서 위와 같이 작성하였습니다.이 상황에서, em이 주입된 queryFactory 싱글톤 빈을 받아서 MemberRepositoryImpl이 생성될 때 그 queryFactory를 주입한다고 생각하면 될까요??이렇게 작성하였을 때, basicTest는 통과하였습니다.하지만 searchTest에서는 result가 비어있었습니다.그래서 처음에 생각했을 때는, 시작메소드에서 JPAQueryFactory를 빈으로 등록했지만, 여기는 Test이기 때문에 시작 메소드를 실행하지 않았고 따라서 제대로 동작하지 않았다고 생각했었습니다.하지만 그렇다면 뭔가 컴파일 오류가 난다던지, basicTest가 불통과된다던지 했었을 텐데, 그러지 않은 것을 보니 무언가 다른 이유가 있을거라 생각합니다.조금 난해한 질문일 수는 있지만, 위와 같은 제 생각의 흐름에서 어떤 부분이 잘못되었는지 말씀해 주실 수 있으실까요??또한 condition에서 setTeamName을 제거했을 때는, result를 출력했을 때, member3와 member4가 나왔고 assertThat을 그에 맞게 수정하였더니 Test가 통과되었습니다.즉, setTeamName 조건을 더했을 때, search가 제대로 동작하지 않는 것인데, 이유가 무엇인지 모르겠습니다. 아래에 전체 코드를 첨부하겠습니다.MemberRepositoryImplpackage study.querydsl.repository; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import study.querydsl.dto.MemberSearchCondition; import study.querydsl.dto.MemberTeamDto; import study.querydsl.dto.QMemberTeamDto; import javax.persistence.EntityManager; import java.util.List; import static org.springframework.util.StringUtils.hasText; import static study.querydsl.entity.QMember.member; import static study.querydsl.entity.QTeam.team; //MemberRepository + "Impl" 형식을 맞춰야 한다. public class MemberRepositoryImpl implements MemberRepositoryCustom{ private final JPAQueryFactory queryFactory; //시작 메소드에서 JPAQueryFactory를 스프링 빈으로 등록해둠 //em이 주입된 queryFactory 싱글톤 빈을 받아온 것 //MemberRepositoryImpl이 생성될 때 그 queryFactory를 주입한다. public MemberRepositoryImpl(JPAQueryFactory queryFactory){ this.queryFactory = queryFactory; } @Override //회원명, 팀명, 나이(ageGoe, ageLoe) public List<MemberTeamDto> search(MemberSearchCondition condition) { return queryFactory .select(new QMemberTeamDto( member.id, member.username, member.age, team.id, team.name)) .from(member) .leftJoin(member.team, team) .where(usernameEq(condition.getUsername()), teamNameEq(condition.getTeamName()), ageGoe(condition.getAgeGoe()), ageLoe(condition.getAgeLoe())) .fetch(); } private BooleanExpression usernameEq(String username) { return hasText(username) ? member.username.eq(username) : null; } private BooleanExpression teamNameEq(String teamName) { return hasText(teamName) ? member.username.eq(teamName) : null; } private BooleanExpression ageGoe(Integer ageGoe) { return ageGoe == null ? null : member.age.goe(ageGoe); } private BooleanExpression ageLoe(Integer ageLoe) { return ageLoe == null ? null : member.age.loe(ageLoe); } } MemberRepositoryTestpackage study.querydsl.repository; 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.dto.MemberSearchCondition; import study.querydsl.dto.MemberTeamDto; import study.querydsl.entity.Member; import study.querydsl.entity.Team; import javax.persistence.EntityManager; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @Transactional class MemberRepositoryTest { @Autowired EntityManager em; @Autowired MemberRepository memberRepository; @Test public void basicTest() { Member member = new Member("member1", 10); memberRepository.save(member); Member findMember = memberRepository.findById(member.getId()).get(); assertThat(findMember).isEqualTo(member); List<Member> result1 = memberRepository.findAll(); assertThat(result1).containsExactly(member); List<Member> result2 = memberRepository.findByUsername("member1"); assertThat(result2).containsExactly(member); } @Test public void searchTest() { Team teamA = new Team("teamA"); Team teamB = new Team("teamB"); em.persist(teamA); em.persist(teamB); 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); em.persist(member1); em.persist(member2); em.persist(member3); em.persist(member4); MemberSearchCondition condition = new MemberSearchCondition(); condition.setAgeGoe(35); condition.setAgeLoe(40); condition.setTeamName("teamB"); List<Member> all = memberRepository.findAll(); List<MemberTeamDto> result = memberRepository.search(condition); System.out.println("all = " + all); System.out.println("result = " + result); assertThat(result).extracting("username").containsExactly("member4"); } } 이때 다음과 같이 변경하면 테스트가 통과됩니다. @Test public void searchTest() { Team teamA = new Team("teamA"); Team teamB = new Team("teamB"); em.persist(teamA); em.persist(teamB); 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); em.persist(member1); em.persist(member2); em.persist(member3); em.persist(member4); MemberSearchCondition condition = new MemberSearchCondition(); condition.setAgeGoe(30); condition.setAgeLoe(40); // condition.setTeamName("teamB"); List<Member> all = memberRepository.findAll(); List<MemberTeamDto> result = memberRepository.search(condition); System.out.println("all = " + all); System.out.println("result = " + result); assertThat(result).extracting("username").containsExactly("member3", "member4"); }
- 미해결실전! Querydsl
sql 줄바꿈
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 완전 강의 내용은 아닌데... sql 자동 줄바꿈 format_sql: true하면 되는 거 아닌가요...? 왜 저는 안 될까요?
- 미해결실전! Querydsl
Querydsl select coalesce enum
users.authority 는 enum 입니다. queryFactory .select(users.authority.coalesce(UserAuthority.None) ~ authority 값이 null 이면 None 값을 넣어서 값을 반환하고 싶습니다. 근데 No enum constant ~ 하면서 에러가 나네요 아마 select 할 때 authority 가 null 값인데 enum 에는 null 이 없어서 그런거 같은데요 어떻게 해결할 수 있을까요??
- 미해결실전! Querydsl
Dto inner class에서의 사용..
안녕하세요 토이프로젝트에서 저는 Dto 양이 많아져서 Dto inner class 를 사용하고있는데 @QueryProjection 선언이 안됩니다 순수한 DTO에서만 사용하고, DTO inner class 내부에서는 사용 못 하나요?? public class ReviewDto { @Getter @Setter @ToString @QueryProjection public static class ReviewsForAdminSearch { private Long id; private String clubName; private Integer yearMonthNum; private String badge; private String bookName; } }
- 미해결실전! Querydsl
queryDsl vs @Query
안녕하센요 @Query를 사용해서 쿼리 사용하는것과 QueryDsl의 어떤 차이가 있는지 성능상 어떤면이 좋은지 알고 싶습니다
- 미해결실전! Querydsl
연관관계 없는 엔티티 외부 조인과 각각의 테이블 조회 2번 해서 비교하는 것에대한 질문 드립니다.
안녕하세요 늘 좋은 강의와 댓글 달아주셔서 감사드립니다. 이해하기 쉽도록 케이스를 적었습니다 1. 토론리뷰 테이블과 마일리지 테이블이 연관관계 없이 존재한다고 가정2. 토론리뷰 테이블의 id가 마일리지 fkey 컬럼에 존재할 경우 마일리지 지급 상태 O 이라는 가정입니다 ^^.. 저 같은 경우는 연관관계가 없을때 외부 조인 사용하는 경우는 여러 쿼리를 날리는 것이 아닌 한 번에 처리 해서 속도 향상을 위해서 연관관계가 없는 외부 조인을 사용한다고 이해했습니다 (왜냐하면 토론리뷰 조회 쿼리와, 마일리지 전체 조회 쿼리를 가져와서 id = fkey 비교하는것보다 연산 속도가 빠를거라고 추측..) 그런데 Tuple 타입으로 변환되는 외부 조인을 사용할 경우는 service와 controller까지 넘어가지 않도록 repository내에서 값을 변환, 처리한 다음 넘기라고 하셨는데 그렇게 될 경우 Repository에서 값을 빼내기 위해 for문을 돌아야하거나, 어쩔수없이 Controller로 데이터를 넘겼다면 프론트 단으로 데이터를 보낸 다음, 프론트에서 for문을 돌아 회원 id가 있는 경우와 마일리지의 fkey가 존재하는 경우를 조회해서 마일리지 지급 유무를 체크할 수 밖에 없지 않나 ?? 라는 생각이 듭니다...ㅠㅠㅠ 결국은 for문을 사용해야해서 속도적으로 어떤 이점이 있을까 라는 생각이 들어 질문하게 되었습니다. 이렇게 연관관계가 맺어져있지 않을 경우는 타입이 Tuple일 수 밖에 없는데 이렇때 어떤 방식으로 접근하는게 올바른 방법일지 질문드립니다 감사합니다!! 혹은 .. Tuple 타입 데이터를 어떻게 다뤄야 할까요..??? ㅠ
- 미해결실전! Querydsl
@QueryProjection 추가 후 빌드시 에러
안녕하세요 강의 완강 후 차근차근 프로젝트에 적용해보고있는데요 QueryProjection 어노테이션을 추가하면 빌드 실패가 되고 있는데 어떤 부분을 찾아봐야할까요? 감사합니다
- 미해결실전! Querydsl
subquery를 여러개 사용을 할려고 합니다.
아래와 같이 게시판 테이블과 게시판의 코맨트 테이블과 게시판의 좋아요 테이블의 3개의 테이블로 구성이 되어 있습니다. 여기서 게시판의 아이디와 게시판의 아이디 별로 코맨트의 갯수와 카운트의 갯수를 뽑아와서 코맨트 갯수 + 카운트 갯수의 순으로 게시판을 정렬을 할려고 하는데 querydsl에서 아래와 같이 서브쿼리를 사용을 하면 오류가 나는데.. 이럴 경우에는 어떤 식으로 해결을 하면 좋을까요? queryFactory.select(board.id, JPAExpressions.select(boardComment.count()) .from(boardComment) .where(boardComment.boardId.eq(board.id)) + JPAExpressions.select(boardLike.count()) .from(boardLike) .where(boardLike.board.id.eq(board.id)) ) .from(board) .fetch();
- 미해결실전! Querydsl
다대다 Projeciton
영한님 안녕하세요 혹시 저번에 강의하셨던 것 중에 order -orderItem -Item 식으로 다대다 연결관계 테이블이 있었는데 만약에 Order를 조회하는데 거기에 포함되는 Item을 전부가져오려면 Projection을 어떻게하면될까요? 밤새 찾아보고 시도해봤는데 모르겠네요 답변해주시면 감사하겠습니다 ㅠㅠ
- 미해결실전! Querydsl
QueryDsl 메소드에 대한 질문있습니다.
이해를 돕기위해 코드 첨삭합니다. 대략적인 코드의 내용은 유저가 시험을 풀고 유저가 푼 문제를 긁어와서 그 문제들의 한 필드(Temporary) 업데이트 즉, 제출한 시험문제 전체를 업데이트하는 그런코드입니다. Service ------------------------------------------------------------------------------------------ @Transactional @Override public ExamMultiSubjectUpdateResponseDto updateExamTemporary(Long courseUserSeq,Long examSeq) { CourseUser courseUser = courseUserRepository.findById(courseUserSeq) .orElseThrow(() -> new RestException(HttpStatus.NOT_FOUND, "찾을 수 없는 유저-과정 입니다. courseUserSeq = " + courseUserSeq)); Exam exam = examRepository.findBySeq(examSeq) .orElseThrow(() -> new RestException(HttpStatus.NOT_FOUND, "일치하는 시험을 찾을 수 없습니다. examSeq=" + examSeq)); //유저가 시험보기를 누른 첫 스타트 시작시간 가져오기 // (객관식 개수가 0 일수도 있고 주관식개수가 0 일수도 있기때문에 2개의 메소드진행) timeCheckMultiple(courseUserSeq, exam); timeCheckSubjective(courseUserSeq, exam); //유저-과정에 등록된 유저가 객관식, 주관식에 모든 임시데이터를 가져온다. String tYn = "Y"; List<ExamMultipleChoiceResult> multiEntityList = examMultipleChoiceResultRepository.findAllByCourseUserSeqAndTemporaryYn(courseUserSeq,tYn); List<ExamSubjectiveResult> subjectEntityList = examSubjectiveResultRepository.findAllByCourseUserSeqAndTemporaryYn(courseUserSeq,tYn); //시험 테이블에 등록된 주관식 객관식 개수 Integer objCnt = exam.getObjCnt(); Integer subCnt = exam.getSubCnt(); log.info("해당과정을 듣는 유저가 입력한 객관식 = {} :: 해당과정을 듣는 유저가 입력한 등록한 주관식 = {}",multiEntityList.size(),subjectEntityList.size()); // 시험 테이블에 등록된 개수들과 유저가 입력한 개수의 조건 비교 if (multiEntityList.size() + subjectEntityList.size() == objCnt+subCnt){ ExamMultiSubjectUpdateResponseDto examMultiSubjectUpdateResponseDto = examRepository.updateTemporary(multiEntityList, subjectEntityList,courseUser); return examMultiSubjectUpdateResponseDto; } else if (!(multiEntityList.size() + subjectEntityList.size() > 0)){ throw new RestException(HttpStatus.BAD_REQUEST,"제출해야 할 주관식,객관식 데이터가 없습니다."); } else { throw new RestException(HttpStatus.BAD_REQUEST,"모든 객관식, 주관식에 답을 입력해주세요."); } } QueryDsl ---------------------------------------------------------------------------------------- @Override public ExamMultiSubjectUpdateResponseDto updateTemporary(List<ExamMultipleChoiceResult> multiEntityList, List<ExamSubjectiveResult> subjectEntityList, CourseUser courseUser) { //유저가 체크한 문제를 임시 상태(temporaryYn)에서 제출상태로 변경 Y 면 임시 저장상태 N 이면 제출한상태 long multi = queryFactory .update(qExamMultipleChoiceResult) .set(qExamMultipleChoiceResult.temporaryYn, "N") .where(qExamMultipleChoiceResult.in(multiEntityList)) .execute(); long subject = queryFactory .update(qExamSubjectiveResult) .set(qExamSubjectiveResult.temporaryYn, "N") .where(qExamSubjectiveResult.in(subjectEntityList)) .execute(); em.flush(); em.clear(); if (multi == 0 || subject == 0){ throw new RestException(HttpStatus.BAD_REQUEST,"시험 제출에 실패하였습니다."); } //Ip주소가 프록시나 로드밸런서를 통해 호출되는 경우 로드밸런서의 IP가 나온다 //이 경우를 방지하기 위해 X-Forwarded-For 값을 확인하고 없을 경우 getRemoteAddr()을 사용한다. HttpServletRequest req = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest(); String ip = ClientsUtils.getRemoteIP(req); //유저 시험 채점 테이블 기본값 세팅 (유저가 시험 제출을하면 관리자가 어떤유저가 제출한건지 알기위함.) //유저가 이미 제출했던 시험이 있는지 검증 if (!examUserRepository.existsByCourseUserSeq(courseUser.getSeq())){ examUserRepository.save(new ExamUser(courseUser,0.0,null,"Y","N",null, LocalDateTime.now(),null,ip,null)); } else { throw new RestException(HttpStatus.NOT_FOUND,"이미 제출하셨던 시험이 있습니다."); } //위 em.flush(),em.clear() 로 인해 //ExamMultiSubjectUpdateResponseDto 에 업데이트한 쿼리가 담기지않아 새로 호출 List<ExamMultipleChoiceResult> reFindMulti = examMultipleChoiceResultRepository.findAllByCourseUserSeq(courseUser.getSeq()); List<ExamSubjectiveResult> reFindSubject = examSubjectiveResultRepository.findAllByCourseUserSeq(courseUser.getSeq()); return ExamMultiSubjectUpdateResponseDto.builder() .multiEntityList(reFindMulti) .subjectEntityList(reFindSubject) .build(); } 위 코드에서 제가 궁금한 점은 1. QueryDsl 메소드안에서 위처럼 examUserRepository(DI :: 의존성주입)를 써도되는지..혹은 서비스단에서 처리하는게 맞는지.. 2. 위 코드에서 지양해야 하는점이있는지.. 피드백주시면 감사하겠습니다..
- 미해결실전! Querydsl
벌크 연산 후 영속성 컨텍스트 초기화에 대해 질문이 있습니다.
말씀해주신대로 이미 영속화 되어있는 상태에서 벌크연산이을 해도 디비로 작업하고 영속성 컨텍스트와 달라져 초기화를 하라고 말씀해주셨는데요, 영속화되있는 상태에서 select를 해도 쿼리가 나가는것이 querydsl일 경우인것이고 JPA에서는 객체를 통해 가져오면 이미 캐시되어있는 데이터를 가져와 디비 쿼리도 치지 않는다고 이해해도 될까요?
- 미해결실전! Querydsl
quertdsl에서 projection을 이용해 @onetoMany dto를 내리고싶을때
프로젝션을 이용한 결과 반환을 배웠는데요, 보통 양방향일 경우 1:n 관계는 조인해서 같이 반환하고 싶을때 fetchjoin()만 이용했다가 디비상으로는 1:n 이지만 단방향인 경우에 querydsl의 projection을 이용해서 dto를 내릴순 없을까요 ? https://bbuljj.github.io/querydsl/2021/05/17/jpa-querydsl-projection-list.html 이런 예제들처럼 양방향 1:n에 대한 예제는 많이 보이는데 단방향인 경우에는 예제가 없는거같아서... 여러 시도를 해봤는데 막히고 있어 궁금합니다 jooq 같은 라이브러리를 써야하는지, querydsl로는 해결방법이 없을까요? 예를 들면 .. TeamDto { String teamName; List<MemberDTO> members; } 이런 구조를 querydsl로 바로 표현할순 없는지..
- 미해결실전! Querydsl
{0},{1},{2}에 의미를 잘 모르겟습니다.
String result = queryFactory .select(Expressions.stringTemplate("function('replace', {0}, {1}, {2})", member.username, "member", "M")) .from(member) .fetchFirst(); 1분에 강사님께서 {0},{1},{2} {}안에 있는걸 0번 1번 2번이라고 말씀하셨는데 파라미터의 무엇을 넣어주는건가요?
- 미해결실전! Querydsl
queryDsl 조회 후 service 에서 다시 N+1 호출 발생
안녕하세요. 영한님. 좋은 강의 덕분에 실무에서 잘 사용하고 있습니다. 감사합니다. 강의를 통해 습득한 queryDsl 을 실무에 적용하면서 이해가 안되는 상황이 생겨서 질문하려고 합니다. queryDsl 을 이용해서 아래처럼 promotion, promotionContent 를 조회 하고 promotion != null 경우 promotionContent 과 oneToMany 양방향 연관관계인 artBoardLink 를 조회해서 promotionContent 에 참조해주고 있습니다. 쿼리는 분명히 아래 코드 실행 시점에 의도한대로 실행이 되는데요. 디버깅을 하거나 조회된 artBoardLink 를 service 레이어에서 접근을 하게 되면 N+1 쿼리가 실행이 됩니다. 임시로 @BatchSize(size=20) 으로 N+1 쿼리 실행 횟수는 줄였지만 완벽한 해결 방법은 아닌거 같아서 질문드리러 왔습니다. 호출하는 service 레이어의 메소드에 @Transactional(readOnly=true) 도 사용중인데 ㅠ_ㅠ 분명 queryDsl 코드 실행 시점에 의도한 select 쿼리가 호출이 되는데 왜 service 레이어에서 artBoardLink 접근 시 다시 쿼리가 발생하는건가요? 해당 이슈에 대한 조언도 부탁드릴수 있을까요?