해결된 질문
작성
·
772
1
안녕하세요.
현재 JPA강의를 통해 회사내 프로젝트중인 직장인 입니다.
실무 중에 강의의 복합키 매핑과는 조금 다른 내용이 있어 며칠을 고민하다 문의 드립니다.
각각 복합키를 가진 두 개의 테이블이 있습니다.
두 테이블은 code라는 공통 컬럼이있고 다대일관계로 매핑을 구성하려고 합니다.
@EmbeddedId관계를 이용해 구성하려고 합니다.
code 컬럼만 매핑시키는 방법을 찾지 못해 문의 남겨드립니다.
현재 문제의 테이블입니다.(회사프로젝트 테이블이라 자세히 올려드리는 못하는 점 양해 부탁드립니다.)
Company Table은 code, biznumber 두 개의 pk로 구성돼 있습니다.
Contract Table 역시 code, module 두 개의 pk로 구성돼 있습니다.
저는 두 테이블에서 code라는 컬럼만 갖고 다대일 매핑을 구현하고 싶습니다.
즉 복합키를 각각 가진 두 개의 테이블에서 각각 하나의 컬럼만을 이용해 다대일 매핑을 구현하고 싶습니다.
제가 에러 내용과 과정을 올리고싶은데 회사코드라 올리면 문제가 생길까 싶어 이렇게 말로 표현드려 죄송합니다.
답변 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 인턴에 달린 댓글을 저희가 확인을 못해서 답변이 많이 늦게 되었습니다. 죄송합니다.
그리고 도움이 되셨길 바래요 :)
0
안녕하세요, 인프런 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의 명세에 규정된 방법이 아니기 때문에, 일부 엔티티 매니저 구현체에서는 지원하지 않을 수 있습니다. 이런 경우에는 별도의 조인 컬럼을 추가하는 방법을 고려해보실 수도 있습니다.
혹시 이렇게 구현했을 때 에러가 발생하는지에 대한 내용을 자세히 알고 싶으시다면, 본문에 언급하신 회사 코드 등의 민감한 정보를 표현하지 않는 형태로 구체적인 에러 내용과 과정을 공유해주시면 더 정확한 도움을 드릴 수 있을 것 같습니다.
더 궁금한 점이 있으시면 언제든지 물어보세요!
안녕하세요.
먼저 답변 달아주셔서 감사드립니다.
해당 내용을 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
아닙니다. 선생님 바쁘신 와중에 이렇게 답글 달아주셔서 감사드립니다. 덕분에 해당 문제 해결했습니다. 앓던 이가 빠진 기분입니다. ㅠㅠㅠ 너무 감사드립니다.