JPA 1์ฐจ ์บ์‹ฑ์„ ์ด์šฉํ•œ ์„ฑ๋Šฅ ํŠœ๋‹, ๊ทธ๋ฆฌ๊ณ  1์ฐจ ์บ์‹ฑ์ด ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์™€ ์šฐํšŒ๋ฒ•

1. ์„œ๋ก 

์ง„ํ–‰์ค‘์ธ ํ”„๋กœ์ ํŠธ์—์„œ ์•„๋ž˜ ์‚ฌ์ง„๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. 

 

 

๊ธฐ๋Šฅ ์„ค๋ช…๋ถ€ํ„ฐ ๊ฐ„๋‹จํžˆ ํ•˜๋ฉด

๋ณธ์ธ์ด ์˜ฌ๋ฆฐ ๊ณต๊ณ ๊ธ€์ด ์žˆ์œผ๋ฉด ํŠน์ • ๋…ธ๋™์ž์—๊ฒŒ ์ผ์ž๋ฆฌ๋ฅผ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. 

์ด๋•Œ ๋…ธ๋™์ž์˜ ์ถœ์—ญ ๊ฐ€๋Šฅํ•œ ๋‚ ์งœ์™€ ๊ณต๊ณ ๊ธ€์˜ ์ถœ์—ญ ๋‚ ์งœ๋ฅผ ๋น„๊ตํ•˜์—ฌ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

 

๊ธฐ์—…์€ ๋…ธ๋™์ž์—๊ฒŒ ์ผ์ž๋ฆฌ๋ฅผ ์ œ์•ˆํ•  ๋•Œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ณต๊ณ ๊ธ€์„ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ๋‹ค. ๋™์‹œ์— ๊ฐ ๊ณต๊ณ ๊ธ€์€ ์—ฌ๋Ÿฌ ๋‚ ์„ ์„ ํƒํ•˜์—ฌ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด 1,2,3์ผ์„ ์ผํ•˜๋Š” ๊ณต๊ณ ๊ธ€ A์™€ 2,3,4์ผ์„ ์ผํ•˜๋Š” ๊ณต๊ณ ๊ธ€ B๊ฐ€ ์žˆ๊ณ , C๋ผ๋Š” ๋…ธ๋™์ž๋Š” 2์ผ๋‚  ์ถœ์—ญ์ด ํ™•์ •๋œ ์ƒํ™ฉ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. 

๊ทธ๋Ÿผ ๊ธฐ์—…์€ C๋…ธ๋™์ž์—๊ฒŒ ๊ณต๊ณ  A์˜ 1,3์ผ, ๊ณต๊ณ  B์˜ 3,4์ผ์„ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.  

 

 

 

์š”์ฒญ JSON์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

{
  "resumeId": 1,
  "offerJobPostRequest": [
    {
    	"jobPostId": 1,
    	"workDateIdList": [1,2]
    },
    {
    	"jobPostId": 1,
    	"workDateIdList": [3,4]
    }
  ]

 

์ด์ œ ๋‚ด๊ฐ€ ํ•ด์•ผํ•  ์ผ์€ ์š”์ฒญ์˜จ pk ๊ฐ’๋“ค์ด ์‹ค์ œ๋กœ ์žˆ๋Š” ๊ฐ’์ธ์ง€ ํ™•์ธํ•ด์•ผ ํ•˜๊ณ  ๊ฐ workDateId ๊ฐ’๋“ค์ด jobPostId์™€ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ๋งบ์–ด์ ธ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผํ•œ๋‹ค. 

 

๋ฆฌํŽ™ํ† ๋ง ์ „ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ์—ˆ๋‹ค. 

public void offerJobPost(Long companyId, OfferRequest request) {
    Member company = memberRepository.findById(companyId)
            .orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
    Resume resume = resumeRepository.findByIdWithMember(request.getResumeId())
            .orElseThrow(() -> new CustomException(ErrorCode.RESUME_NOT_FOUND));
    Member worker = resume.getMember();

    // ์ฝ”๋“œ ์ƒ๋žต

    for (OfferJobPostRequest offerJobPostRequest : request.getOfferJobPostRequest()) {
        // jobPost ์กฐํšŒ
        JobPost jobPost = jobPostRepository.findById(offerJobPostRequest.getJobPostId())
                .orElseThrow(() -> new CustomException(ErrorCode.JOB_POST_NOT_FOUND));

        // ์ฝ”๋“œ ์ƒ๋žต

        // jobPostId, workDateId๋กœ workDate ์กฐํšŒ
        List<WorkDate> workDateEntityList = workDateRepository.findByIdList(offerJobPostRequest.getWorkDateIdList(), jobPost.getId())

        // ์ฝ”๋“œ ์ƒ๋žต
    }
    // ์ฝ”๋“œ ์ƒ๋žต
}

 

 

 

 

 

2. ๋ฌธ์ œ์ 

๋ฐ˜๋ณต๋ฌธ ์•ˆ์— ์ฟผ๋ฆฌ ํ˜ธ์ถœ ๋กœ์ง์ด ๋“ค์–ด๊ฐ€์žˆ์–ด N๊ฐœ์˜ ์ฟผ๋ฆฌ๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋‹ค. ์œ„์™€ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ๋‹จ์ˆœํžˆ fetch join์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ default_batch_fetch_size๋ฅผ ์ ์šฉํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค.

 

๊ทธ๋ƒฅ ๊ฒ€์ฆ ๊ณผ์ •์—์„œ ๊ทธ๋ ‡๊ฒŒ ํ˜ธ์ถœ๋  ์ˆ˜ ๋ฐ–์— ์—†๋Š” ์ƒํ™ฉ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 

 

 

 

 

3. ํ•ด๊ฒฐ ์‹œ๋„(1)

์šฐ์„  db์—์„œ idList ๊ฐ’์œผ๋กœ ๋ฏธ๋ฆฌ ์ „๋ถ€ ์กฐํšŒํ•œ ๋‹ค์Œ id ๊ฐ’์„ key๋กœ ๊ฐ–๊ณ  ๋ณธ์ธ์„ value๋กœ ๊ฐ–๋Š” Map์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐํ•˜๋ ค ์‹œ๋„ํ–ˆ๋‹ค. request ์—์„œ JobPostIdList ์™€ WorkDateIdList๋ฅผ ์ถ”์ถœํ•œ ๋‹ค์Œ Map์œผ๋กœ ๋ณ€ํ™˜์‹œ์ผœ ์ฃผ์—ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ฐ˜๋ณต๋ฌธ์—์„œ ๊ฐ’์ด ํ•„์š”ํ•  ๋•Œ db์—์„œ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ map์—์„œ ์กฐํšŒํ–ˆ๋‹ค. 

    public void offerJobPost_(Long companyId, OfferRequest request) {
        Member company = memberRepository.findById(companyId)
                .orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
        Resume resume = resumeRepository.findByIdWithMember(request.getResumeId())
                .orElseThrow(() -> new CustomException(ErrorCode.RESUME_NOT_FOUND));
        Member worker = resume.getMember();

        // ์ฝ”๋“œ ์ƒ๋žต


        List<Long> jobPostIdList = request.getOfferJobPostRequest().stream()
                .map(OfferJobPostRequest::getJobPostId)
                .collect(Collectors.toList());

        List<Long> workDateIdList = request.getOfferJobPostRequest().stream()
                .flatMap(o -> o.getWorkDateIdList().stream())
                .collect(Collectors.toList());

        Map<Long, JobPost> jobPostMap = jobPostRepository.findByIdList(jobPostIdList)
                .stream()
                .collect(Collectors.toMap(JobPost::getId, Function.identity()));

        Map<Long, WorkDate> workDateMap = workDateRepository.findByIdList(workDateIdList)
                .stream()
                .collect(Collectors.toMap(WorkDate::getId, Function.identity()));


        for (OfferJobPostRequest offerJobPostRequest : request.getOfferJobPostRequest()) {
            // jobPost ์กฐํšŒ
            JobPost jobPost = jobPostMap.get(offerJobPostRequest.getJobPostId());

            // ์ฝ”๋“œ ์ƒ๋žต
            
            // jobPostId, workDateId๋กœ workDate ์กฐํšŒ
            List<WorkDate> workDateEntityList = offerJobPostRequest.getWorkDateIdList().stream()
                    .map(workDateMap::get)
                    .collect(Collectors.toList());

            // ์ฝ”๋“œ ์ƒ๋žต
        }
        // ์ฝ”๋“œ ์ƒ๋žต
    }

 

์–ด๋–ป๊ฒŒ ๋ณด๋ฉด Redis ๊ฐ™์€ ์บ์‹œ๋ฅผ ์ด์šฉํ•˜๋Š” ๋Š๋‚Œ์ด์—ˆ๋‹ค. 

์œ„ ์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ๋ฐ”๊พผ ํ›„ ์ฟผ๋ฆฌ๋Š” ๋”์ด์ƒ N๋ฒˆ ๋‚˜๊ฐ€์ง„ ์•Š์•˜์ง€๋งŒ ํ—ˆ์ ์ด ์žˆ์—ˆ๋‹ค. ์กฐํšŒํ•œ workDate ๊ฐ’์ด JobPost์™€ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ๋งบ์–ด์ง€์ง€ ์•Š์€, ์ฆ‰ JobPost์™€๋Š” ์ „ํ˜€ ์—‰๋šฑํ•œ workDate๊ฐ€ ์กฐํšŒ๋œ๋‹ค ํ•ด๋„ ์ด๋ฅผ ๋ฐœ๊ฒฌํ•  ๋ฐฉ๋ฒ•์ด ์—†๋‹ค. 

 

๊ณ ์‹ฌ ๋์— JPA 1์ฐจ ์บ์‹ฑ์„ ๋– ์˜ฌ๋ ธ๋‹ค.

 

 

 

 

3. ํ•ด๊ฒฐ ์‹œ๋„(2)

JPA 1์ฐจ ์บ์‹ฑ์„ ์ด์šฉํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค. 

๊ฒ€์ฆ ๋กœ์ง ์ด์ „์— id๊ฐ’๋“ค์— ํ•ด๋‹นํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ์—ญ์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋„ฃ์€ ํ›„ ๋‹ค์‹œ ์กฐํšŒํ•˜๋ฉด ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ–ˆ๋‹ค. 

 

 

JPA 1์ฐจ ์บ์‹œ๋ž€?

1์ฐจ ์บ์‹œ๋ž€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence Context) ๋‚ด์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ์บ์‹œ์ด๋‹ค. 

 

1์ฐจ ์บ์‹œ์˜ ๊ณผ์ •์€ ์„ธ ๊ฐ€์ง€ ๊ณผ์ •๊ณผ ๊ฐ™๋‹ค. 

  1. ์กฐํšŒ ์‹œ ์ฒ˜์Œ 1์ฐจ ์บ์‹œ์— ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํƒ์ƒ‰์„ ํ•œ๋‹ค. -> ๋งŒ์•ฝ ์žˆ์œผ๋ฉด ๋ฐ”๋กœ ๋ฆฌํ„ด
  2. ์กฐํšŒ ๊ฒฐ๊ณผ 1์ฐจ ์บ์‹œ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•ด ๊ฐ’์„ ํƒ์ƒ‰ํ•œ๋‹ค.
  3. ํƒ์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๋‹ค์Œ ํƒ์ƒ‰์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก 1์ฐจ ์บ์‹œ์— ์ €์žฅํ•œ๋‹ค.

 

 

์กฐํšŒํ•œ ์—”ํ‹ฐํ‹ฐ๋“ค์€ 1์ฐจ ์บ์‹œ์— ํ•ญ์ƒ ์ €์žฅํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. EntityManager๋Š” ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„์ด๊ธฐ ๋•Œ๋ฌธ์— ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๋ฉด 1์ฐจ ์บ์‹œ๋„ ์ง€์›Œ๋ฒ„๋ฆฐ๋‹ค. ๊ต‰์žฅํžˆ ์งง์€ ์ฐฐ๋‚˜์˜ ์ˆœ๊ฐ„์—๋งŒ ์žฅ์ ์ด ์žˆ๋‹ค.

 

public void offerJobPost_(Long companyId, OfferRequest request) {
    Member company = memberRepository.findById(companyId)
            .orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
    Resume resume = resumeRepository.findByIdWithMember(request.getResumeId())
            .orElseThrow(() -> new CustomException(ErrorCode.RESUME_NOT_FOUND));
    Member worker = resume.getMember();

    // ์ฝ”๋“œ ์ƒ๋žต


    List<Long> jobPostIdList = request.getOfferJobPostRequest().stream()
            .map(OfferJobPostRequest::getJobPostId)
            .collect(Collectors.toList());

    List<Long> workDateIdList = request.getOfferJobPostRequest().stream()
            .flatMap(o -> o.getWorkDateIdList().stream())
            .collect(Collectors.toList());

    // 1์ฐจ ์บ์‹ฑ ์ฒ˜๋ฆฌ
    jobPostRepository.findByIdList(jobPostIdList);
    workDateRepository.findByIdList(workDateIdList);


    for (OfferJobPostRequest offerJobPostRequest : request.getOfferJobPostRequest()) {
        // jobPost ์กฐํšŒ
        JobPost jobPost = jobPostRepository.findById(offerJobPostRequest.getJobPostId())
                .orElseThrow(() -> new CustomException(ErrorCode.JOB_POST_NOT_FOUND));

        // ์ฝ”๋“œ ์ƒ๋žต

        // jobPostId, workDateId๋กœ workDate ์กฐํšŒ
        List<WorkDate> workDateEntityList = workDateRepository.findByIdList(workDateIdList, jobPost.getId());

        // ์ฝ”๋“œ ์ƒ๋žต
    }
    // ์ฝ”๋“œ ์ƒ๋žต
}

 

๋™์ผ ํŠธ๋žœ์žญ์…˜์—์„œ ์ด์ „์— ์กฐํšŒํ•œ ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•ด์„  DB์—์„œ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์–ด์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์— for๋ฌธ ์•ˆ์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๋• ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ–ˆ๋‹ค. 

 

 

ํ•˜์ง€๋งŒ ๋‚ด ์ƒ๊ฐ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์•˜๋‹ค. 

๊ฒฐ๊ณผ๋Š” jobPost๋Š” 1์ฐจ ์บ์‹œ์—์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ workDate๋Š” ๊ทธ๋Ÿฌ์ง€ ๋ชปํ–ˆ๊ณ  ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ”๋‹ค. 

 

 

์ด์œ ๋ฅผ ์ฐพ์•„๋ณด๋‹ˆ 1์ฐจ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„  ๋ช‡๊ฐ€์ง€ ์กฐ๊ฑด์ด ์žˆ์—ˆ๋‹ค. 

 

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜์ž๋ฉด

1์ฐจ ์บ์‹œ๋Š” PK๊ฐ€ ์•„๋‹ˆ๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค

 

1์ฐจ ์บ์‹œ ๋™์ž‘ ์กฐ๊ฑด

  1. ์บ์‹œ์— ์ €์žฅ๋˜๋Š”๊ฑด ์ปค์Šคํ…€ ์ฟผ๋ฆฌ(JPQL)์„ ์‚ฌ์šฉํ•ด๋„ ๋ฌธ์ œ ์—†์ด 1์ฐจ ์บ์‹œ์— ์ €์žฅ๋œ๋‹ค. 
  2. ๋‹จ, ์บ์‹œ์—์„œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š”๊ฑด PK๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœํ•œ find (entity manager๋ฅผ ์“ธ๋•Œ find() ๋ฉ”์„œ๋“œ ํ˜น์€ data-jpa์˜ findById)์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค.
  3.  select c from Comment c where c.id = :paramId ์™€ ๊ฐ™์€ PK๊ธฐ๋ฐ˜ JPQL๋„ ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ์•„๊ฐ„๋‹ค. (em.createQuery ๊ฐ€ ํ˜ธ์ถœ๋จ)
  4. ํŠธ๋žœ์žญ์…˜์ด ์ข…๋ฃŒ๋˜๊ฑฐ๋‚˜, flush()๋  ๊ฒฝ์šฐ ์บ์‹œ๋Š” ์ดˆ๊ธฐํ™”๋œ๋‹ค.
  5. PK ๊ธฐ๋ฐ˜ find ์กฐํšŒ๋ฅผ ํ•˜๋”๋ผ๋„, ์ฒ˜์Œ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์—”ํ‹ฐํ‹ฐ๋ฉด ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ์•„๊ฐ„๋‹ค.

 

 

2, 3๋ฒˆ ์กฐ๊ฑด์ด ์ค‘์š”ํ•˜๋‹ค.

JobPost๋ฅผ ์กฐํšŒํ•  ๋• findById๋กœ ์กฐํšŒํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— 1์ฐจ ์บ์‹œ์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ, WorkDate๋ฅผ ์กฐํšŒํ•  ๋• ์ปค์Šคํ…€ JPQL์„ ์‚ฌ์šฉํ–ˆ์„ ๋ฟ๋”๋Ÿฌ pk๋งŒ์„ ์‚ฌ์šฉํ•œ ์กฐํšŒ๋„ ์•„๋‹ˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— 1์ฐจ ์บ์‹œ ์กฐํšŒ๊ฐ€ ๋˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ์ด๋‹ค. 

 

 

 

3. ํ•ด๊ฒฐ ์‹œ๋„ (3) - ์ตœ์ข…

์ตœ์ข…์œผ๋กœ JPA 1์ฐจ ์บ์‹ฑ๊ณผ Map ๋‘ ๋ฐฉ๋ฒ•์„ ๋ชจ๋‘ ์ด์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ–ˆ๋‹ค. ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค. 

 

    public void offerJobPost(Long companyId, OfferRequest request) {
        Member company = memberRepository.findById(companyId)
                .orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
        Resume resume = resumeRepository.findByIdWithMember(request.getResumeId())
                .orElseThrow(() -> new CustomException(ErrorCode.RESUME_NOT_FOUND));
        Member worker = resume.getMember();

        List<Long> jobPostIdList = new ArrayList<>();
        List<Long> workDateIdList = new ArrayList<>();

        for (OfferJobPostRequest offerJobPostRequest : request.getOfferJobPostRequest()) {
            jobPostIdList.add(offerJobPostRequest.getJobPostId());
            workDateIdList.addAll(offerJobPostRequest.getWorkDateIdList());
        }

        // jpa 1์ฐจ ์บ์‹ฑ์„ ์œ„ํ•œ ์กฐํšŒ ๋ฐ ์บ์‹œ Map ์ƒ์„ฑ
        Map<Long, List<WorkDate>> workDateMap = getWorkDateMap(jobPostIdList, workDateIdList);

        for (OfferJobPostRequest offerJobPostRequest : request.getOfferJobPostRequest()) {
            JobPost jobPost = jobPostRepository.findById(offerJobPostRequest.getJobPostId())
                    .orElseThrow(() -> new CustomException(ErrorCode.JOB_POST_NOT_FOUND));

            // ์ฝ”๋“œ ์ƒ๋žต

            List<WorkDate> workDateEntityList = workDateMap.get(jobPost.getId());
            if (workDateEntityList.size() != offerJobPostRequest.getWorkDateIdList().size()) {
            	throw new CustomException(ErrorCode.WORK_DATE_NOT_MATCH);
            }
        }
        // ์ฝ”๋“œ ์ƒ๋žต
    }

    private Map<Long, List<WorkDate>> getWorkDateMap(List<Long> jobPostIdList, List<Long> workDateIdList) {
        jobPostRepository.findByIdList(jobPostIdList);
        List<WorkDate> workDateList = workDateRepository.findByIdList(workDateIdList);

        Map<Long, List<WorkDate>> workDateMap = new HashMap<>();
        for (WorkDate workDate : workDateList) {
            Long jobPostId = workDate.getJobPost().getId();
            // Key๊ฐ€ jobPostId์ธ List ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜, ์ƒˆ๋กœ ์ƒ์„ฑ
            List<WorkDate> innerList = workDateMap.computeIfAbsent(jobPostId, k -> new ArrayList<>());
            // innerMap์— workDateId์™€ workDate๋ฅผ ์ถ”๊ฐ€
            innerList.add(workDate);
        }
        return workDateMap;
    }

 

์ด์ „์—” JobPost์™€ WorkDate ๊ฐ๊ฐ์˜ pk๊ฐ’์„ key๋กœ ์„ค์ •ํ•˜๊ณ  value๋ฅผ ๊ฐ ์—”ํ‹ฐํ‹ฐ๋กœ ์„ค์ •ํ–ˆ๋‹ค๋ฉด ์ด๋ฒˆ์—”

 

JobPost๋Š” 1์ฐจ ์บ์‹œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์กฐํšŒํ•˜๊ณ 

WorkDate๋Š” ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ๋งบ์–ด์ง„ JobPost์˜ pk ๊ฐ’์„ key๋กœ ์„ค์ •ํ•˜๊ณ  List<WorkDate>๋ฅผ value๋กœ ์„ค์ •ํ•ด์ฃผ์–ด ์บ์‹œ ์—ญํ• ์„ ํ•˜๋Š” Map์„ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค. ์ด๋ ‡๊ฒŒ JobPost์™€๋Š” ๊ด€๊ณ„๊ฐ€ ์—†๋Š” WorkDate๊ฐ€ ์กฐํšŒ๋˜๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

 

 

 

4. ๊ฒฐ๋ก 

JPA ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฐฐ์šฐ๋ฉฐ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ํŠน์ง•์œผ๋กœ 1์ฐจ ์บ์‹ฑ, ์“ฐ๊ธฐ ์ง€์—ฐ, ๋ณ€๊ฒฝ ๊ฐ์ง€.. ๋“ฑ ํŠน์ง•๋“ค์„ ํ•™์Šตํ–ˆ๊ณ  ๊ธฐ์–ตํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ 1์ฐจ ์บ์‹œ๋ฅผ ์ด์šฉํ•ด์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์„ ํ•˜์ง€ ๋ชป ํ–ˆ๊ณ  ์ง€๊ธˆ๊นŒ์ง€ ์‚ฌ์šฉํ•ด๋ณธ์ ๋„ ์—†์—ˆ๋‹ค. ์ •ํ™•ํžˆ ์‚ฌ์šฉํ•  ์ผ์ด ์—†์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค. 

 

๋‚˜์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœํ•  ์ƒํ™ฉ์ด ์žˆ๋‹ค๋ฉด 1์ฐจ ์บ์‹œ๋ฅผ ์ ๊ทน ์ด์šฉํ•˜๋Š”๊ฑธ ์ถ”์ฒœํ•œ๋‹ค. ๋˜ ์บ์‹œ ๊ธฐ๋Šฅ์„ ํ•  ์ˆ˜ ์žˆ๋Š” Map์„ ์ž„์‹œ๋กœ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์•„ ๋ณด์ธ๋‹ค. Map์€ ์ƒ๊ฐ๋ณด๋‹ค ์“ธ ์ƒํ™ฉ์ด ์ž์ฃผ ์ƒ๊ธฐ๋Š” ๊ฒƒ ๊ฐ™๋‹ค. 

๋‹จ, Map์€ ์ž˜๋ชป ์‚ฌ์šฉํ•  ์‹œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์˜ ์›์ธ์ด ๋˜๋ฏ€๋กœ ์ž˜ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. 

 

 

 

 

 

์ฐธ๊ณ 

https://velog.io/@im_h_jo/JPA-1%EC%B0%A8-%EC%BA%90%EC%8B%9C-%EC%9E%91%EB%8F%99-%EC%A1%B0%EA%B1%B4

https://dingdingmin-back-end-developer.tistory.com/entry/Spring-Boot-JPA-1%EC%B0%A8-%EC%BA%90%EC%8B%9C-%EC%A0%95%EB%A6%AC