해결된 질문
작성
·
1.6K
·
수정됨
0
table : prodPlan
pk : factoryCode, prodplanId
column : itemCode ...
table : Item
pk : factoryCode, materialCode
column : itemName...
테이블 구조는 이렇고 저는 MSSQL을 연동해서 기본적인 테이블 생성은 MSSQL에서 생성하여 사용하고 있습니다.
prodPlan(N) : item(1) 로 ManyToOne 매핑을 하려고 하는데요
@Entity
@IdClass(ProdPlanId.class)
public class ProdPlan {
@Id
private String factoryCode;
@Id
private Long prodplanId;
@Column(name = "ITEM_CODE")
private String itemCode;
//...
@ManyToOne
@JoinColumn(name = "FACTORY_CODE",referencedColumnName = "FACTORY_CODE",insertable = false, updatable = false)
@JoinColumn(name = "ITEM_CODE",referencedColumnName = "MATERIAL_CODE",insertable = false, updatable = false)
private Item item;
}
@Entity
@IdClass(ItemId.class)
public class Item {
@Id
private String factoryCode;
@Id
private String materialCode;
//...
}
@JoinColumn에 name 속성이 외래키의 이름을 정의하는거라고 알고 있습니다.
factoryCode는 외래키가 아니고 두 테이블에서 복합키이자 기본키입니다.
(복합키는 class ProdPlanId implements Serializable을 사용하여 @IdClass 어노테이션을 사용하였습니다.)
그래서 위에 코드와 같이 구현을 하면 FACTORY_CODE가 중복컬럼에러가 나서 일단 insertable, updatable = false로 임시해결을 했는데 해결을 한게 아닌 거 같아서 다른 방법이 있나 찾아보던 중 inheritancetype.table_per_class 이 구조가 조금 비슷해보여서 진행하려 했으나 @JoinColumn에서 어떻게 사용해야 하는지 모르겠습니다. (factoryCode는 외래키가 아닙니다! 찾아보니 일대일 매핑만 나왔습니다ㅠㅠ)
읽기전용이 아닌 prodPlan 테이블의 ITEM_CODE와 Item 테이블의 MATERIAL_CODE를 조인하려 했는데요. 그럴려면 @Column itemCode를 지우고 사용해야 중복컬럼에러를 피할 수 있었습니다. @Column itemCode를 선언하고 조인하는 방법은 없을까요?
답변 2
1
안녕하세요. 혜정님
이 경우 좀 특수하게 매핑을 해야하는데요. 다음 코드를 참고해주세요.
package com.example.jpacomposite.entity;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
@Data
@Entity
@Table(name = "ITEM")
@IdClass(ItemId.class)
public class Item implements Serializable {
@Id
@Column(name = "FACTORY_CODE")
private String factoryCode;
@Id
@Column(name = "MATERIAL_CODE")
private String materialCode;
@Column(name = "MATERIAL_NAME")
private String materialName;
}
package com.example.jpacomposite.entity;
import jakarta.persistence.Embeddable;
import lombok.Data;
import java.io.Serializable;
@Data
@Embeddable
public class ItemId implements Serializable {
private String factoryCode;
private String materialCode;
}
package com.example.jpacomposite.entity;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
@Data
@Entity
@Table(name = "PRODPLAN")
@IdClass(ProdPlanId.class)
public class ProdPlan implements Serializable {
@Id
@Column(name = "FACTORY_CODE")
private String factoryCode;
@Id
@Column(name = "PRODPLAN_ID")
private String prodPlanId;
@Column(name = "ITEM_CODE")
private String itemCode;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "FACTORY_CODE", referencedColumnName = "FACTORY_CODE", insertable = false, updatable = false),
@JoinColumn(name = "ITEM_CODE", referencedColumnName = "MATERIAL_CODE", insertable = false, updatable = false)
})
private Item item;
}
package com.example.jpacomposite.entity;
import jakarta.persistence.Embeddable;
import lombok.Data;
import java.io.Serializable;
@Data
@Embeddable
public class ProdPlanId implements Serializable {
private String factoryCode;
private String prodPlanId;
}
package com.example.jpacomposite;
import com.example.jpacomposite.entity.Item;
import com.example.jpacomposite.entity.ProdPlan;
import jakarta.persistence.TypedQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
public class ItemAndProdPlanTest {
@Autowired
private TestEntityManager entityManager;
@Test
public void testFindProdPlanWithItem() {
Item item = new Item();
item.setFactoryCode("FAC001");
item.setMaterialCode("MAT001");
item.setMaterialName("Material 1");
entityManager.persist(item);
ProdPlan prodPlan = new ProdPlan();
prodPlan.setFactoryCode("FAC001");
prodPlan.setProdPlanId("PP001");
prodPlan.setItemCode(item.getMaterialCode());
entityManager.persist(prodPlan);
entityManager.flush();
entityManager.clear();
TypedQuery<ProdPlan> query = entityManager.getEntityManager().createQuery("SELECT p FROM ProdPlan p WHERE p.factoryCode = :factoryCode AND p.prodPlanId = :prodPlanId", ProdPlan.class);
query.setParameter("factoryCode", "FAC001");
query.setParameter("prodPlanId", "PP001");
List<ProdPlan> resultList = query.getResultList();
assertThat(resultList).hasSize(1);
ProdPlan foundProdPlan = resultList.get(0);
assertThat(foundProdPlan.getItem()).isNotNull();
assertThat(foundProdPlan.getItem().getFactoryCode()).isEqualTo(item.getFactoryCode());
assertThat(foundProdPlan.getItem().getMaterialCode()).isEqualTo(item.getMaterialCode());
assertThat(foundProdPlan.getItem().getMaterialName()).isEqualTo(item.getMaterialName());
}
}
감사합니다.
0
안녕하세요. 이혜정님
질문이 명확하게 잘 이해가 되지 않습니다.
다음 내용을 적어주시면 좋겠습니다.
create table DDL을 바로 테이블을 생성할 수 있을 정도로 정확하게 적어주세요. 테스트를 위해서 강의에 나온 H2 데이터베이스를 기준으로 만들 수 있도록 해주세요.
create table DDL에서 PK, FK 제약조건도 포함해주세요.
두 테이블을 조인해서 조회하는 SQL을 적어주세요. 실행가능한 SQL이어야 합니다.
샘플 예제 INSERT SQL을 넣고, 조인해서 조회하는 SQL도 남겨주세요. 그리고 그 결과가 어떻게 되는지도 남겨주세요.
감사합니다.
create table ITEM (
FACTORY_CODE varchar(6),
MATERIAL_CODE varchar(20),
MATERIAL_NAME varchar(30),
constraint PK_ITEM primary key(FACTORY_CODE, MATERIAL_CODE)
)
create table PRODPLAN (
FACTORY_CODE varchar(6),
PRODPLAN_ID varchar(20),
ITEM_CODE varchar(20),
constraint PK_PRODPLAN primary key(FACTORY_CODE, PRODPLAN_ID),
foreign key (FACTORY_CODE, ITEM_CODE) references ITEM(FACTORY_CODE, MATERIAL_CODE)
)
위에 포함했습니다!
select * from prodplan a
left join item b
on a.factory_code = b.factory_code
and a.item_code = b.material_code
insert into item values ('000001', '00010', '치약')
insert into prodplan values ('000001', '202304170001', '00010')
FACTORY_CODE는 ITEM과 PRODPLAN의 복합키 중 하나입니다!
감사합니다.
아 이해했습니다 readOnly로 매핑을 하는 수 밖에 없군요 감사합니다!