JPA

brave_chicken·2024년 6월 14일

잇(IT)생 챌린지

목록 보기
72/90

info.txt

5. 연관관계

  • 일대일
  • 일대다
  • 다대일
  • 다대다

1) 일대일

  • @OneToOne
  • 주테이블에 외래키를 갖고 있으며 단방향
  • 연관된 모든 테이블에 데이터가 삽입되도록 하려면 Cascade옵션을 적용
    @OneToOne(cascade = CascadeType.ALL)
  • @JoinColumn의 name속성을 통해 조인할 컬럼을 정의하고 name은 컬럼명

2) 일대다

  • pk - fk관계를 명시
    ex. 한 부서에 근무하는 직원목록
    주문번호에 주문한 품목들
    카테고리에 포함된 상품목록들
    사원 한명의 경력사항들 ...
  • @OneToMany
  • One에 해당하는 엔티티에 다에 해당하는 엔티티를 List로 가지고 있도록 정의
  • 일대다 관계에서 @JoinColumn은 왜ㅣ래키 테이블에 외래키로 정의할 컬럼명
    @JoinColumn(name = "userKey")
    외래키 테이블의 userKey와 조인하겠다는 의미
  • 대상 테이블의 어떤 컬럼과 매핑되어있는지 엔티티컬럼명을 명시한다.

3) 다대일

  • 항상 다대일인지 일대다인지 평가하는 기준은 어느테이블을 기준으로 잡고 작업하냐에 따라 달라진다.
  1. 연관관계방향
  • 단방향
  • 양방향
  1. spring data JPA

실습

PublicInfoEntity

공용으로 사용될 컬럼을 별도의 클래스로 빼고 상속받아서 사용

@Data
@MappedSuperclass
public class PublicInfoEntity {
    @CreationTimestamp
    private Date creationDate;
    @UpdateTimestamp
    private Date updateDate;
}

EmpEntity

//단방향으로 작업
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "myemp")
public class EmpEntity extends PublicInfoEntity {
    @Id
    private String userId;
    private String name;
    private String addr;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "userPrivateId")
    private PrivateInfoEntity infoEntity;


    public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity) {
        this.userId = userId;
        this.name = name;
        this.addr = addr;
        this.infoEntity = infoEntity;
    }

    //경력사항은 한 사람이 여러 개 가질 수 있다.
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "userKey")
    private List<HistoryEntity> historyEntityList = new ArrayList<>();

    @ManyToOne
    @JoinColumn(name = "deptId")
    private DeptEntity dept;

    public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity, List<HistoryEntity> historyEntityList) {
        this.userId = userId;
        this.name = name;
        this.addr = addr;
        this.infoEntity = infoEntity;
        this.historyEntityList = historyEntityList;
    }
}

PrivateInfoEntity

myemp테이블과 1:1로 매핑되는 사적정보를 담고있는 엔티티

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "userInfo")
public class PrivateInfoEntity {
    //시퀀스를 PK로 하지 않고 아이디를 PK
    @Id
    private String userInfoId;
    private String info1;
    private String info2;
}

HistoryEntity

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "myhistory")
public class HistoryEntity {
    @Id
    @GeneratedValue
    private Long historyId;
    private String company;
    private String content;

    public HistoryEntity(String company, String content) {
        this.company = company;
        this.content = content;
    }
}

DeptEntity

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "mydept")
public class DeptEntity {
    @Id
    @GeneratedValue
    @Column(name = "deptNo")
    private Long id;
    private String name;
    private String mgr;

    public DeptEntity(String name, String mgr) {
        this.name = name;
        this.mgr = mgr;
    }
}

EmpEntityTest

@SpringBootTest
@Transactional
@Rollback(value = false)
class EmpEntityTest {
    //JPA의 스펙에서 제공하는 기능을 제대로 사용할 수 있도록 제공
    //@Autowired와 같은 역할도 수행
    //@PersistenceContext는 EntityManager를 빈으로 주입할 때 사용하는 어노테이션
    @PersistenceContext
    EntityManager entityManager;
    @Test
    public void test1(){
        //사원의 기본정보와 사원의 시크릿정보를 입력받아서 두테이블에 저장
        PrivateInfoEntity privateInfo1 =
                new PrivateInfoEntity("bts1","태양과 듀엣","솔로");
        PrivateInfoEntity privateInfo2 =
                new PrivateInfoEntity("bts2","Seven","올림픽곡");
        PrivateInfoEntity privateInfo3 =
                new PrivateInfoEntity("bts3","춤모야","조교");
        PrivateInfoEntity privateInfo4 =
                new PrivateInfoEntity("bts4","제대했다","너무해");
        PrivateInfoEntity privateInfo5 =
                new PrivateInfoEntity("kbr","싱어송라이터","바람바람바람");


        EmpEntity emp1 = new EmpEntity("bts1","지민","광주",privateInfo1);
        EmpEntity emp2 = new EmpEntity("bts2","정국","부산",privateInfo2);
        EmpEntity emp3 = new EmpEntity("bts3","제이홉","광주",privateInfo3);
        EmpEntity emp4 = new EmpEntity("bts4","석진","천안",privateInfo4);
        EmpEntity emp5 = new EmpEntity("kbr","범룡","청주",privateInfo5);

        entityManager.persist(emp1);
        entityManager.persist(emp2);
        entityManager.persist(emp3);
        entityManager.persist(emp4);
        entityManager.persist(emp5);

        //object references an unsaved transient instance - save the transient instance before flushing 오류 긁어서 구글링하면 해결가능
    }
    @Test
    public void readtest1(){
        EmpEntity empEntity = entityManager.find(EmpEntity.class,"bts4");
        System.out.println(empEntity);
    }
    @Test
    public void test2(){
        //경력사항, emp기본정보, 시크릿정보 모두 저장하기
        List<HistoryEntity> historyEntityList = new ArrayList<>();
        historyEntityList.add(new HistoryEntity("A사","front react개발"));
        historyEntityList.add(new HistoryEntity("B사","Entity개발"));
        historyEntityList.add(new HistoryEntity("C사","보안개발"));

        EmpEntity emp = new EmpEntity("bts7", "슈가", "대구",
                                new PrivateInfoEntity("bts7","화양연화","래퍼"),
                                historyEntityList);
        entityManager.persist(emp);
    }
    @Test
    public void readtest2(){
        EmpEntity empEntity = entityManager.find(EmpEntity.class,"bts7");
        System.out.println(empEntity);
    }

    @Test
    public void test3(){
        //부서, 기본정보, 시크릿, 히스토리
        DeptEntity dept1 = new DeptEntity("전산실","김서연");
        entityManager.persist(dept1);

        //경력
        List<HistoryEntity> historyEntityList = new ArrayList<>();
        historyEntityList.add(new HistoryEntity("A사","front react개발"));
        historyEntityList.add(new HistoryEntity("B사","Entity개발"));
        historyEntityList.add(new HistoryEntity("C사","보안개발"));

        //사원정보, 시크릿, 경력정보, 부서정보
        EmpEntity emp = new EmpEntity("bts7", "슈가", "대구",
                new PrivateInfoEntity("bts7","화양연화","래퍼"),
                historyEntityList,dept1);
        entityManager.persist(emp);
    }

    @Test
    public void readtest3(){
        EmpEntity empEntity = entityManager.find(EmpEntity.class,"bts7");
        System.out.println(empEntity);
    }
}

미션.[실습2]

CategoryEntity(EmpEntity같은느낌)

  • category 테이블
  • categoryId 는 시퀀스 : 기본키
  • categoryName
  • info

ProductEntity(History같은느낌)

  • product 테이블
  • productNo : 시퀀스 - 기본키
  • productName , info , image : String
  • price : int
  • 상품등록일, 상품수정일 추가하기 (PublicInfo extends하기)
  • category는 다수의 product를 가질 수 있다.(@OneToMany관계)
  • EmpEntityTest와 동일하게 insert와 find테스트
  • 임의의 데이터 카테고리 3개 프로덕트 5개 넣고 테스트

CategoryEntity

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "category")
public class CategoryEntity  {
    @Id
    @GeneratedValue
    private Long categoryId;
    private String categoryName;
    private String info;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "product")
    private List<ProductEntity> productEntityList = new ArrayList<>();

    public CategoryEntity(String categoryName, String info) {
        this.categoryName = categoryName;
        this.info = info;
    }

    public CategoryEntity(String categoryName, String info, List<ProductEntity> productEntityList) {
        this.categoryName = categoryName;
        this.info = info;
        this.productEntityList = productEntityList;
    }
}

ProductEntity

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "product")
public class ProductEntity extends PublicInfoEntity {
    @Id
    @GeneratedValue
    private Long productNo;
    private String productName;
    private String info;
    private String image;
    private int price;
    //CategoryEntity category;
    public ProductEntity(String productName, String info, String image, int price) {
        this.productName = productName;
        this.info = info;
        this.image = image;
        this.price = price;
    }
}

CategoryEntityTest

@SpringBootTest
@Transactional
@Rollback(value = false)
class CategoryEntityTest {
    @PersistenceContext
    EntityManager entityManager;
    @Test
    public void test(){
        List<ProductEntity> productEntityList1 = new ArrayList<>();
        productEntityList1.add(new ProductEntity("식탁","갈색","사진1.jpg",3000));
        productEntityList1.add(new ProductEntity("수납장","녹색","사진4.jpg",1000));

        List<ProductEntity> productEntityList2 = new ArrayList<>();
        productEntityList2.add(new ProductEntity("쇼파","아이보리색","사진2.jpg",5000));
        productEntityList2.add(new ProductEntity("수납장","녹색","사진4.jpg",1000));

        List<ProductEntity> productEntityList3 = new ArrayList<>();
        productEntityList3.add(new ProductEntity("침대","폭신함","사진3.jpg",4000));
        productEntityList3.add(new ProductEntity("이불","흰색","사진5.jpg",2000));



        CategoryEntity category1 = new CategoryEntity("주방가구","식탁과수납장",productEntityList1);
        CategoryEntity category2 = new CategoryEntity("거실가구","쇼파와수납장",productEntityList2);
        CategoryEntity category3 = new CategoryEntity("침구","침대와협탁",productEntityList3);

        entityManager.persist(category1);
        entityManager.persist(category2);
        entityManager.persist(category3);
    }

    @Test
    public void readtest(){
        ProductEntity productEntity = entityManager.find(ProductEntity.class,1L);
        System.out.println(productEntity);

        CategoryEntity categoryEntity = entityManager.find(CategoryEntity.class,1L);
        System.out.println(categoryEntity);
    }
}

본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.

0개의 댓글