inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

자바 ORM 표준 JPA 프로그래밍 - 기본편

복합키 끼리의 매핑 질문 드립니다.

해결된 질문

943

차재욱

작성한 질문수 3

1

안녕하세요.

현재 JPA강의를 통해 회사내 프로젝트중인 직장인 입니다.

실무 중에 강의의 복합키 매핑과는 조금 다른 내용이 있어 며칠을 고민하다 문의 드립니다.

 

 

현재 문제의 테이블입니다.(회사프로젝트 테이블이라 자세히 올려드리는 못하는 점 양해 부탁드립니다.)

  1. Company Table은 code, biznumber 두 개의 pk로 구성돼 있습니다.

  2. Contract Table 역시 code, module 두 개의 pk로 구성돼 있습니다.

  3. 저는 두 테이블에서 code라는 컬럼만 갖고 다대일 매핑을 구현하고 싶습니다.

 

 

 

java jpa

답변 2

1

김영한

안녕하세요. 차재욱님

몇가지 제약이 있기는 하지만 가능은 합니다.

우선 이렇게 적용하려면 복합키는 @IdClass 방식을 사용해야 할 것 같아요.

(실무에서도 복합키 매핑은 @IdClass를 더 권장합니다.)

다음 코드를 참고해주세요.

package com.example.jpacomposite.code2;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import lombok.Data;

@Data
@IdClass(CompanyPK.class)
@Entity
public class Company {

    @Id
    private String code;

    @Id
    private String biznumber;
}

 

package com.example.jpacomposite.code2;

import lombok.Data;

import java.io.Serializable;

@Data
public class CompanyPK implements Serializable {
	private String code;
	private String biznumber;

	public CompanyPK() {
	}

	public CompanyPK(String code, String biznumber) {
		this.code = code;
		this.biznumber = biznumber;
	}
}

 

package com.example.jpacomposite.code2;

import jakarta.persistence.*;
import lombok.Data;


@Data
@IdClass(ContractPK.class)
@Entity
public class Contract {

    @Id
    private String companyCode;

    @Id
    private String moduleCode;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "companyCode", referencedColumnName = "code", insertable = false, updatable = false)
    private Company company;
}
package com.example.jpacomposite.code2;

import lombok.Data;

import java.io.Serializable;

@Data
public class ContractPK implements Serializable {
	private String companyCode;
	private String moduleCode;

	public ContractPK() {
	}

	public ContractPK(String companyCode, String moduleCode) {
		this.companyCode = companyCode;
		this.moduleCode = moduleCode;
	}
}

 

package com.example.jpacomposite.code2;

import jakarta.persistence.EntityManager;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;

import static org.assertj.core.api.Assertions.assertThat;

@DataJpaTest
class CompanyTest2 {

    @Autowired
    EntityManager em;

    @Test
    void go() {
        Company company = new Company();
        company.setCode("code1");
        company.setBiznumber("biznum1");
        em.persist(company);

        Contract contract = new Contract();
        contract.setCompanyCode("code1");
        contract.setModuleCode("module1");
        em.persist(contract);

        em.flush();
        em.clear();

        ContractPK pk = new ContractPK("code1", "module1");
        Contract findContract = em.find(Contract.class, pk);
        System.out.println("findContract = " + findContract);
        Company findCompany = findContract.getCompany();
        assertThat(findCompany.getCode()).isEqualTo(company.getCode());
        assertThat(findCompany.getBiznumber()).isEqualTo(company.getBiznumber());

        em.flush();
    }
}

 

여기서 Contract 클래스의 매핑 부분이 중요한데요.

연관관계를 사용할 수는 있지만 이 연관관계는 읽기 전용으로만 사용하셔야 합니다. 왜냐하면 연관관계가 이미 PK를 통해서 모두 확정이 되어 버리기 때문입니다.

이 필드를 통해서는 연관관계를 읽기만 가능한 것이지요.

 

AI 인턴에 달린 댓글을 저희가 확인을 못해서 답변이 많이 늦게 되었습니다. 죄송합니다.

그리고 도움이 되셨길 바래요 :)

2

차재욱

아닙니다. 선생님 바쁘신 와중에 이렇게 답글 달아주셔서 감사드립니다. 덕분에 해당 문제 해결했습니다. 앓던 이가 빠진 기분입니다. ㅠㅠㅠ 너무 감사드립니다.

0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴입니다.
복합키를 가진 두 개의 테이블에서 code 컬럼만을 이용해 다대일 매핑을 구현하고 싶으시군요. 일반적으로는 @EmbeddedId 어노테이션을 사용하여 복합키를 매핑할 수 있습니다.

@Entity
public class Company {

@EmbeddedId
private CompanyId id;

// 다른 필드들
// ...

}

@Embeddable
public class CompanyId implements Serializable {

private String code;

// getter, setter, equals, hashCode 등 구현
// ...

}

@Entity
public class Contract {

@EmbeddedId
private ContractId id;

// 다른 필드들
// ...

}

@Embeddable
public class ContractId implements Serializable {

private String code;

// getter, setter, equals, hashCode 등 구현
// ...

}

위와 같이 코드를 작성하고, Company와 Contract의 code 필드에 @ManyToOne 어노테이션을 추가하여 다대일 관계를 매핑할 수 있습니다.

그러나 복합키를 가진 테이블에서 일부 컬럼만으로 다대일 매핑을 구현하는 것은 JPA의 명세에 규정된 방법이 아니기 때문에, 일부 엔티티 매니저 구현체에서는 지원하지 않을 수 있습니다. 이런 경우에는 별도의 조인 컬럼을 추가하는 방법을 고려해보실 수도 있습니다.

혹시 이렇게 구현했을 때 에러가 발생하는지에 대한 내용을 자세히 알고 싶으시다면, 본문에 언급하신 회사 코드 등의 민감한 정보를 표현하지 않는 형태로 구체적인 에러 내용과 과정을 공유해주시면 더 정확한 도움을 드릴 수 있을 것 같습니다.
더 궁금한 점이 있으시면 언제든지 물어보세요!

0

차재욱

안녕하세요.

먼저 답변 달아주셔서 감사드립니다.

해당 내용을 JPA에서 지원하지 않는다는 점 확인했습니다.

그럼에도 아무래도 필요하다보니 가능하다면 진행해 보고싶은 마음에 이렇게 다시 문의 드립니다.

 

먼저 달아주신 답변 기반으로 진행한 코드 및 결과 첨부해드립니다.

@Embeddable

CompanyPK.Class

public class CompanyPK implements Serializable{
	private String code;
	private String biznumber;
}

 

@Entity

Company.Class

public class Company extends BaseEntity{	
	@EmbeddedId
	private CompanyPK companyId;
}

 

@Embeddable

ContractPK.Class

public class ContractPK implements Serializable{
	private String companyCode;
	private String moduleCode;
}

 

@Entity

Contract.Class

public class Contract extends BaseEntity{		
	@EmbeddedId
	private ContractPK contractId;
	
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="company_code")
	private Company company;
}

Contract Class에서 Company Class와 다대일 매핑 시도시

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: An association that targets entity 'entity.Company' from entity 'entity.Contract' has 1 '@JoinColumn's but the primary key has 2 columns

와 같은 에러가 발생합니다.

 

다음은

	@MapsId("companyCode")
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="company_code")
	private Company company;

위의 Contract.Class에서 @MapsId("companyCode") 추가시 실행하면

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Property 'company' of entity 'entity.Contract' must have a '@JoinColumn' which references the foreign key column 'null'

이런 오류가 발생합니다.

 

오류 내용일 짐작해보아 하나는 'PK가 2개인데 1개를 찾을 수 없다'로 보이고 나머지 하나는 JoinColumn을 못찾는 듯 합니다.

 

어떤 부분을 개선해야 되는지 알 수 있을까요?

 

또한 복합키에서 @EmbeddedId를 사용해야되는 이유가 있나요?

간단하게 필드에서 @Id, @Id 이렇게 두개로 구현하면 안되는걸까요?

추가 궁금증에 관한 문의 내용도 남겨드립니다.

 

감사합니다. :D

inheritance startegy 선택시 고려사항

0

11

0

Entity 동등성 비교

0

14

1

실무 조언 관련 질문입니다.

0

41

1

H2데이터베이스 파일 생성

0

52

2

서브쿼리 강의에서 ALL 예시 관련 질문드립니다.

0

49

2

수정또는 삭제시 영속성 엔티티에 값이 무조건 있어야 하나요?

0

48

1

JPQL 메소드와 락

0

53

1

Delivery @OneToOne

0

57

1

17강 4~5분대 테이블 값 조회가 안됩니다.

0

89

2

UnsupportedOperationException 발생

0

82

3

H2 Database 연결이 안됩니다.

0

89

2

연관관계 매핑 질문드립니다.

0

82

2

h2데이터베이스 실행오류

0

105

2

persistence.xml

0

103

2

양방향 연관관계에서 연관관계의 주인(mappedBy)을 왜 꼭 정해야 하나요?

0

77

1

영속성 컨텍스트

0

62

1

JPA 프록시

0

90

1

Native Query와 MyBatis

0

63

1

영속성 컨텍스트는 어떤 메모리에 저장되는건가요?

0

84

1

임베디드 타입 예시 코드 관련 질문

0

112

3

명시적 조인에서 별칭을 주면 왜 객체에 접근할 수 있나요

0

91

3

인텔리제이 패키지 커서 단축키 질문

0

106

2

혹시 현재는 ID 데이터 타입이 String이면 안되나요?

0

138

1

양방향 연관관계 시 연관관계 주인을 설정하는 이유

0

68

1