30%
61,600원
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! Querydsl
Querydsl "group_concat" 사용법 질문드려요
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.
- 해결됨실전! Querydsl
tuple로 조회된 결과값을 modelMapper에 담을 수 있을까요?
아래와 같이 querydsl을 사용해서 목록을 조회하고 List로 받은 결과값을 BoardDto 타입으로 변환해서 저장하는것은 잘 됩니다. List<Board> list = queryFactory.select(board) .from(board) .fetch(); List<BoardDto> boardList = new ArrayList<>(); list.forEach(v -> { boardList.add(modelMapper.map(v, BoardDto.class)); });그런데 문제는 아래와 같이 Tuple로 리턴을 받았을때는 어떻게 담아야 할까요?List<Tuple> list = queryFactory.select(board.title, board.content) .from(board) .fetch();검색을 했을 때.. 아래와 같이 사용을 하면 된다고 하는데.. getElements()라는 메소드는 존재하지 않는데 어떻게 저렇게 사용을 하는지 모르겠네요..(현재 자바 8을 사용하고 있습니다.)List<Product> products = productsTuple .stream() .map(p -> { Map<String, Object> maps = new HashMap<>(); p.getElements().forEach(te -> { maps.put(te.getAlias(), p.get(te.getAlias())); }); return modelMapper.map(maps, Product.class)); }) .collect(Collectors.toList());단순하게 DB에 있는 컬럼만을 사용자로 보내주는 경우는 많지 않고 가공을 해서 보내줘야 하는 경우가 대부분인데..querydsl로 tuple데이터를 조회했을 때 modelmapper로 담는 방법이 없을까요? tuple로 조회된 정보들은 Map으로 따로 담아서 view 로 리턴을 해 주는데 그렇게 되면 tuple의 결과값에 따라 map에 넣어주는 데이터들도 많아지고, 중복 비슷한 자료들이 너무 많아져서 보기가 좋지 않은데.. return 할 DTO를 하나 만들어서 그곳에 리턴될 값들으 모두 담아서 리턴을 할 수 있는 방법이 있을까요??예를들어 게시판 테이블에서 조회를 할 때 특정 필드값들을 select하고, 첨부파일 정보를 select하고, 회원 정보를 select를 해서이 3개의 테이블에 있는 필요한 값들을 DTO를 하나 만들어서 그곳에 담아서 리턴을 해 주고 싶은데제가 알고있는 방식은Map<String, Object> map = new HashMap<>(); map.put("id", tuple(user.id)); map.put("title",tuple(board.title)); map.put("fileName", tuple.attach.fileName));위와같은 식으로 맵에 각각 담아서 맵으로 화면에 리턴을 해 주고 있는데이런 값들을 담을 DTO를 아래와 같이 만들고public class returnDTO{ private Long id; private String title; private String filename; }returnDTO 안에 modelmapper나 다른 방법을 사용해서 한꺼번에 담을 수 있는 방법이 있을까요?값이 얼마 없을때는 그냥 사용을 하면 되는데 값이 많아지고, 하나의 메소드 안에서 여러번 가공을 해서 만들어야 할 경우에는 Map을 만드는 작업을 여러번 반복을 해야하는 상황이 발생하다보니 소스가 많이 지저분해지는 느낌이 많이 듭니다.
- 미해결실전! Querydsl
질문드립니다
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]기초적인거라서 예전에 강의를 전부 보고 다시 찾으려고 하니 잘 못찾겠습니다.. (있었는지도 의문?)select 시에 getter 로 가공을 거치는 방법이 있나요?jpaQueryFactory.select( Projections.bean( UserHistoryOutput.Chart.class, userHistory.bodyHeat.avg().divide(10).floatValue().as("bodyHeat"),public class UserHistory extends BaseCreateTimeEntity { ..... public Float getBodyHeat() { return Optional.ofNullable(bodyHeat).orElse(0f) / 10f; } userHistory 에서 getter를 이용하여 뽑아올 경우 divde 10을 해주고 있습니다하지만 querydsl 을 이용해서 하면 순수 데이터를 가공없이 그대로 뽑아오던데dto를 통해서 뽑아오는 방법이 있을까요?
- 미해결실전! Querydsl
2:30초 질문
질문합니다. 동영상과 다르게 작동합니다. 테스트 코드 돌리면 위와 같이 나옵니다.하이버네이트 시퀀스가 없다고 해서Hello 엔터티에 @GeneratedValue(strategy=IDENTITY)를 추가하고 돌렸습니다.깃헙 :https://github.com/InSuChoe/querydsl
- 미해결실전! Querydsl
sql로 처리할 때와 애플리케이션으로 처리할 때 기준이 어떻게 될까요?
A테이블에서 a 칼럼 값과 B테이블에서 b 칼럼 값이 서로 일치하는 데이터를 dto로 만들고 페이징 처리를 해서 컨트롤러로 반환해야 합니다., querydsl로 sql 짜서 하는게 좋을까요? 아니면, A테이블 데이터 가져오고, B테이블 데이터 가져와서 애플리케이션(2중 for문 사용 or 2중 stream 사용)에서 비교해주는게 좋을까요?참고로 A 테이블과 B테이블은 연관관계가 없습니다. 단, 비교 조건이 수시로 바뀔 수 있는 상황입니다.어느게 더 유지보수하기 좋을까요? sql로 처리하면 비교 조건이 바뀔 때 마다 sql을 손봐야하잖아요? 그러면 유지보수도 힘들어지고, 비즈니스 로직이 sql에 녹아들어져 있는 것 같습니다. 또, 조인이 들어가서 속도도 많이 느릴 것 같습니다.애플리케이션에서 처리하면, A 테이블을 조회할 때 데이터 건수가 몇 억 건수라고 가정할 때, 정제되지 않는 데이터가 다 조회되는거라서 조회만으로도 속도가 많이 느려지지 않을까 합니다. 추가로, sql로 처리할 때와 애플리케이션으로 처리할 때 기준이 어떻게 될까요?
- 미해결실전! Querydsl
조인과 패치조인
queryDsl이전의 강의들은 tuple사용하지 않았습니다. 그래서 조인시에select m from Member m join m.team t 이렇게 했지select m,t from Member m join m.team t 이렇게 하지 않았습니다.패치 조인이란건 프록시객체를 초기화 해서 한번에 다 가져오는 join이라고 배웠습니다. 하지만 이런식으로 하면 loaded = true라고 나옵니다.그러면 사실상 위의 쿼리와밑의 fetch join의 차이가 무엇인지 궁금합니다. 요점은select m,t from Member m join m.team t와select m from Member m join fetch m.team는 멤버의 team의 프록시가 생기지 않는다는 결과는 같은데무엇이 다른 지 궁금합니다.
- 해결됨실전! Querydsl
세타조인 관련된 질문입니다.
항상 강의 잘듣고 있습니다.회원의 이름과 팀 이름이 같은 회원을 조회하라는 예제를 듣고 조인 없이 직관적으로 다음과 같은 쿼리를 생각하였는데요.테스트시 빈 결과값이 반환되는것으로 추측됩니다. @Test void theta_join() { em.persist(new Member("teamA")); em.persist(new Member("teamB")); em.persist(new Member("teamC")); List<Member> result = queryFactory .select(member) .from(member) .where(member.username.eq(member.team.name)) .fetch(); System.out.println("result = " + result); // => result = [] assertThat(result).extracting("username").containsExactly("teamA","teamB"); } //----------console log---------- Expecting actual: [] to contain exactly (and in same order): ["teamA", "teamB"] but could not find the following elements: ["teamA", "teamB"] //----------------------------------- 혹시나.. Fetch타입이 LAZY로 되어있어서 그런가 싶어서EAGER로 바꿔봤는데도, 결과가 나오지 않습니다..... 그렇다면...이 쿼리는 왜 작동하지 않는지 궁금합니다.
- 해결됨실전! Querydsl
요청 매핑이 궁금합니다.
우선, 좋은 강의 올려주셔서 정말 감사합니다. 동적 필터를 구현하고 작동도 잘되는데 한 가지 궁금한 것이 생겨 질문을 하게 되었습니다. 강사님 강의 속에서 dto 앞에 어노테이션을 붙이지 않고 포스트맨에서 RequestParam처럼 사용하시는데스프링에서는 저 값을 어떻게 받고 데이터를 처리하는 건가요? 보통 @RequestParam은 들어온 요청 값을 MessageConverter 사용해서 스프링이 처리를 하는 걸로 공부를 했는데 querydsl에서는 어노테이션 하나 안쓰고 dto를 사용하고 데이터를 전송하는데 어떻게 처리하는 지 궁금합니다. 혼자 디버그도 찍어보고 @RequestParam이건 생략이 가능하니 이것을 사용한 건가 해서 넣어보니 포스트맨에서 에러 발생합니다. 너무 궁금합니다....바쁘신데 질문까지 받아주셔서 정말 감사합니다. :)
- 미해결실전! Querydsl
jpa 레포지토리 사용 중 오류
안녕하세요!querydsl과 jparepository 강의를 듣고 참고하여 개인 코딩 공부를 하고 있는 학생입니다.다름이 아니라 좋아요 기능 구현 중 customrepository를 사용하였는데 하단과 같은 오류가 발생해서 문의 드립니다.확인해보니 패키지를 분리하라고 하신 분도 있어서 패키지 분리를 했는데도 동일한 오류가 발생합니다ㅠ.ㅠ이유가 뭘까요..오류Error creating bean with name 'businessLikeService' defined in file [/Users/gimnayeon/Desktop/GreenProject/GrinGreen/out/production/classes/com/grin/GrinGreen/BusinessLike/service/BusinessLikeService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'businessLikeRepository' defined in com.grin.GrinGreen.BusinessLike.repository.BusinessLikeRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.Optional com.grin.GrinGreen.BusinessLike.repository.BusinessLikeRepositoryCustom.exist(java.lang.String,java.lang.Long)! Reason: Failed to create query for method public abstract java.util.Optional com.grin.GrinGreen.BusinessLike.repository.BusinessLikeRepositoryCustom.exist(java.lang.String,java.lang.Long)! No property 'exist' found for type 'BusinessLike'!; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.Optional com.grin.GrinGreen.BusinessLike.repository.BusinessLikeRepositoryCustom.exist(java.lang.String,java.lang.Long)! No property 'exist' found for type 'BusinessLike'!BusinessLike Entity@Entity @Getter @NoArgsConstructor public class BusinessLike { @Id @GeneratedValue @Column(name = "like_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "mail") private Member member; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "business_id") private Business business; @QueryProjection public BusinessLike(Member member, Business business) { this.member = member; this.business = business; } }BusinessLike DTO@Data public class BusinessLikeDto { private Member member; private Long businessId; @QueryProjection public BusinessLikeDto(Member member, Long businessId) { this.member = member; this.businessId = businessId; } }BusinessLike Response DTO@Data public class BusinessLikeResponseDto { private Long BusinessLikeNum; private Boolean check; @QueryProjection public BusinessLikeResponseDto(Long BusinessLikeNum, Boolean check) { this.BusinessLikeNum = BusinessLikeNum; this.check = check; } }BusinessLikeCustomRepositorypublic class BusinessLikeCustomRepositoryImpl implements BusinessLikeRepositoryCustom{ private final JPAQueryFactory queryFactory; public BusinessLikeCustomRepositoryImpl(EntityManager em) { this.queryFactory = new JPAQueryFactory(em); } @Override public Optional<BusinessLike> exist(String mail, Long businessId) { BusinessLike lList = queryFactory .selectFrom(businessLike) .where(businessLike.member.mail.eq(mail), businessLike.business.id.eq(businessId)) .fetchFirst(); return Optional.ofNullable(lList); } public long BusinessLikeNumfind(Long businessId) { return queryFactory .selectFrom(businessLike) .where(businessLike.business.id.eq(businessId)) .fetchCount(); } }BusinessLikeRepository@Transactional(readOnly = true) public interface BusinessLikeRepository extends JpaRepository<BusinessLike, Long>, BusinessLikeRepositoryCustom { }BusinessLikeRepositoryImplpublic interface BusinessLikeRepositoryCustom { Optional<BusinessLike> exist(String mail, Long businessId); long BusinessLikeNumfind(Long businessId); }BusinessLikeService@Slf4j @Service @Transactional @RequiredArgsConstructor public class BusinessLikeService { private final BusinessLikeRepository businessLikeRepository; private final BusinessRepository businessRepository; //좋아요 및 취소 public Boolean pushBusinessLike(BusinessLikeDto businessLikeDto) { businessLikeRepository.exist(businessLikeDto.getMember().getMail(), businessLikeDto.getBusinessId()) .ifPresentOrElse(businessLike -> businessLikeRepository.deleteById(businessLikeDto.getBusinessId()), ()-> { Business business = getBusiness(businessLikeDto); businessLikeRepository.save(new BusinessLike(businessLikeDto.getMember(), business)); }); return true; } @Transactional(readOnly = true) private Business getBusiness(BusinessLikeDto businessLikeDto) { return businessRepository.findById(businessLikeDto.getBusinessId()) .orElseThrow(() -> new IllegalArgumentException("해당 게시글은 존재하지 않습니다.")); } // 좋아요 개수 @Transactional(readOnly = true) public BusinessLikeResponseDto getBusinessLikeInfo(BusinessLikeDto businessLikeDto) { long businessLikeNum = getBusinessLikeNum(businessLikeDto); boolean check = checkPushedLike(businessLikeDto); return new BusinessLikeResponseDto(businessLikeNum, check); } @Transactional(readOnly = true) public boolean checkPushedLike(BusinessLikeDto businessLikeDto) { return businessLikeRepository.exist(businessLikeDto.getMember().getMail(), businessLikeDto.getBusinessId()) .isPresent(); } @Transactional(readOnly = true) public long getBusinessLikeNum(BusinessLikeDto businessLikeDto) { return businessLikeRepository.BusinessLikeNumfind(businessLikeDto.getBusinessId()); } }BusinessLikeServiceTest @SpringBootTest @Transactional public class BusinessLikeServiceTest { @Autowired BusinessLikeService businessLikeService; @Autowired MemberService memberService; @Autowired BusinessService businessService; @Test public void 좋아요() throws Exception{ //given Member member = new Member(); member.setNickname("testMember"); member.setMail("testMember@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()); memberService.join(member); Member findMember = memberService.findOne(member.getMail()); Business business = new Business(); business.setBusinessName("테스트밥집"); business.setHomepage("test.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()); businessService.join(business); Business findBusiness = businessService.findOne(business.getId()); //when BusinessLikeDto businessLikeDto = new BusinessLikeDto(findMember,findBusiness.getId()); businessLikeService.pushBusinessLike(businessLikeDto); System.out.println("businessLikeDto = " + businessLikeDto.getBusinessId());; //then assertEquals(1,businessLikeService.getBusinessLikeInfo(businessLikeDto).getBusinessLikeNum()); } }
- 해결됨실전! Querydsl
QueryDSL 사용 시 order by case 구문 질문 드립니다!
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 안녕하세요 혼자 프로젝트를 만들다가 특정 Type 별로 정렬을 수행해야 하는 경우가 생겨 검색하다 QueryDSL을 이용하여 orderBy Case 구문을 사용하는 방법이 궁금하여 질문을 남기게 되었습니다.정확하게는 OneToMany 관계인 경우, Many 쪽의 요소를 정렬하고자 할 때의 방법을 잘 모르겠어서 질문드려요!Store < === > Menu위의 두 엔티티가 OneToMany 관계로 연관되어 있고, 매장 상세 정보에서 메뉴를 출력하는 경우, Menu의 Type 필드( MAIN, DESSERT, DRINK, BEVERAGE)를 기준으로 orderBy를 수행하려고 합니다.현재 제가 구현한 방식은< 특정 매장에 속한 메뉴 조회하는 로직 >< 매장의 정보를 조회하는 코드 >매장을 조회하는 로직에서 한 번에 처리하려고 하니 방법이 생각나지 않아 두 쿼리를 분리하여 메뉴는 위의 코드에서 조회하고, 아래에서는 매장의 나머지 정보만 불러오는 형식으로 구현돼있습니다.또한 매장 정보 조회 시, DTO에선 순수 매장 정보만을 불러오는 형식이라 메뉴를 조회하는 쿼리가 중복으로 나가진 않습니다!연관 관계에 놓여 있는 엔티티를 별도의 조회 쿼리를 작성하여 불러오는 것이 이런 경우 맞는 방법인지 아니면 제가 아직 부족하여 놓친 하나로 합쳐서 조회할 수 있는 좋은 방법이 있는지 궁금합니다!!긴 글 읽어주셔서 감사합니다!
- 미해결실전! Querydsl
queryDsl의 쿼리를 한 클래스에 모아놓을 수 있을까요?
private final JPAQueryFactory queryFactory; List<AccountForm> fetchResult = queryFactory.select(Projections.bean(AccountForm.class, account.id .... , account.dong , account.aptName , account.dongHo)) .from(account) .where(userRoleEqCond(role)) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch(); return fetchResult;Service 클래스에서 위와같은 식으로 쿼리를 만들경우 회원 정보를 불러오는 쿼리가 여러군데 있을 경우 각각 클래스마다 거의 동일한 조건의 쿼리문을 만들게 됩니다.다만 조건을 다르게 해서 where(~~) 부분을 다르게 할 수는 있겠지만, 클래스가 다를 경우에는 거의 동일한 코드가 반복되고, 어떨때는 AccountForm.class 라는 DTO의 클래스도 중복 생성되는 문제가 있어서 고민을 하다가 혹시나 테이블별로 쿼리를 모아놓은 패키지를 만들어서 그쪽에 클래스들을 모아놓을려고 만들어봤는데 오류가 납니다.private final JPAQueryFactory queryFactory; public static List<AccountForm> selectAccountQuery(Pageable pageable, UserRole role) { List<AccountForm> fetchResult = queryFactory.select(Projections.bean(AccountForm.class, account.id .... , account.dong , account.aptName , account.dongHo)) .from(account) .where(userRoleEqCond(role)) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch(); return fetchResult;위와같은 식으로 패키지와 클래스를 따로 분리를 해서 메소드들을 static으로 만들었는데 데이터를 불러오지 못하고, 오류가 납니다.오류는 private final JPAQueryFactory queryFactory; 이 값이 static으로 되어있지 않다고 해서 static으로 바꿀려고 했는데 private static final JPAQueryFactory queryFactory = null;위와같은 식으로만 되어버려서 소스상에서 보더라도 null로 초기화를 시켜버리니까 당연히 데이터를 불러오지 못하게 되는데..혹시 실무에서 위와같은 식으로 중복되는 쿼리가 많을 경우에 처리를 어떤식으로 하는지 궁금합니다.중복되더라도 어쩔 수 없이 그대로 사용을 해야 하는지, 아니면 중복되는 부분을 제거하는 방법이 있는지 궁금합니다.줄일 수 있을 것 같은데 방법을 모르겠습니다.
- 해결됨실전! Querydsl
상속관계 매핑을 지양해야 하는가?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]https://inf.run/P9aM안녕하세요 영한님, 위 질문 및 답변에 대하여 몇가지 추가적으로 질문이 있습니다.저도 김문근님의 고민과 같은 고민을 하고 있었는데 JPA강의에서도 관련된 질문이 있는지 계속 찾아보았습니다만 속이 뻥 뚫리는 답이 없어서 여기까지 왔습니다.그런데 한가지 영한님이 계속 말씀하시는 부분은 "실무에서는 상속관계 매핑을 꼭 필요할 때 부분적으로 사용한다" 이었습니다. 그렇다면 상속관계 매핑을 실무에서 잘 사용하지 않는 이유는 무엇인가요?위 예제처럼 상속관계 매핑(싱글테이블)전략을 사용하지 않고 한 테이블에 데이터들이 들어간다면 비어있는 값은 null로 되는 것은 상속관계 매핑과 다를게 없을 것 같은데 이 부분에서의 이점은 무엇일까요? 오늘 하루 이 고민하다 시간이 훌쩍 지나갔네요... 영한님과 JPA의 시작과 끝을 함께하고 싶습니다.강의 정말 감사합니다!!
- 미해결실전! Querydsl
Serializable serialVersionUID 질문 드립니
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (아니오)[질문 내용]Serializable serialVersionUID 질문 드립니다안녕하세요 강사님!여태까지 개발하다가왜를 생각하지 않고 아래와 같이 Dto 를 만든 때 implements Serializable serialVersionUID사용해왔는데요 Dto를 만들때 사용하지 않으면 Serializable, serialVersionUID 발생할 수 있는 문제점이 뭔지왜 사용해야 하는지 설명해 주실 수 있을까요구글링 하다가 쉽게 이해가 되지 않아 질문 드립니다수고하세요..
- 미해결실전! 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"); }