임베디드 타입

  • 새로운 값 타입을 직접 정의할 수 있음
  • JPA 는 임베디드 타입이라 함
  • 기본 값 타입을 모아 만들어서 복합 값 타입이라 부름
  • int,String 과 같은 값 타입

 

임베디드 타입 장점

  • 재사용성
  • 높은 응집도
  • 해당 값 타입만 사용하는 의미 있는 메소드 생성 가능
  • 임베디드 타입을 포함한 모든 값 타입은 값 타입을 소유한 엔티티에 생명주기를 의존

 

임베디드 타입 사용 방법

  • @Embeddable : 값 타입 정의하는 곳에 표시
  • @Embedded : 값 타입 사용하는 곳에 표시
  • 기본 생성자 필수

 

임베디드 타입과 테이블 매핑

: 임베디드 타입을 쓴것과 안 쓴것의 회원 테이블은 이전과 똑같음을 알 수 있습니다.

 

 - 테이블은 데이터를 다루는 개념이기에 변경되지 않도록 설계하는 것이 좋습니다.

 - 엔티티의 경우 메소드까지 신경을 써야하므로 공통 기능은 묶어서 사용하는게 사용성이 더 좋습니다.

 

 

임베디드 타입과 테이블 매핑

  • 임베디드 타입은 엔티티의 값일 뿐입니다.
  • 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같습니다.
  • 객체와 테이블을 아주 세밀하게 매핑하는 것이 가능합니다. ( 프로젝트가 커질 수록 세밀한게 좋다 )
  • 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많습니다.

 

임베디드 타입과 엔티티

  • 임베디드 타입 멤버 안에 엔티티 객체도 들어 올 수 있습니다

- PhoneNumber 라는 임베디드 객체는 PhoneEntity 라는 엔티티를 가질 수 있음

 

 

사용 예시

  • 회원 테이블의 [ Address ( city, street, zipcode ) ] , [ WorkPeriod ( Order, Send, ArriveDateTIme ) ] 임베디드 타입을 정의

 

발생오류

1. EntityManagerFactory 빈을 등록 안한 오류 <해결완료>

 

[ 기존 코드 ]

    @Bean
    public EntityManager getEm() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory();
        return emf.createEntityManager();
    }

[ 수정 코드 ]

    @Bean
    public EntityManagerFactory getEmf() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("5xik");
        return emf;
    }
    
    @Bean
    public EntityManager getEm() {
        EntityManagerFactory emf = getEmf();
        EntityManager em = emf.createEntityManager();
        return em;
    }

 

 

2. 테이블이 업데이트 되지 않는 오류 < 해결완료 >

<property name="hibernate.hbm2ddl.auto" value="update" />

 

 

3. 커밋 시기를 save 함수 내에서 작동하도록 변경 < 해결완료 >

 

 [ 기존 코드 ]

테스트 코드에서 의존성 주입받은 EntityManager 를 통해 커밋을 해주는 방식을 사용하기 위해 시도

  -> 트랜잭션호출 생성 함수에서 NPE 발생

 

[ 수정 코드 ]

public Member save(Member member) {
    tx.begin();
    try {
        em.persist(member);
        tx.commit();
    } catch (Exception e) {
        tx.rollback();
    } finally {
        //em.close();
    }
    //mf.close();
    return member;
}
    @Test
    @Commit
    void insertData() {
        Member member = new Member();
        member.setName("test");
        member.setPhonenumber("01011");
        member.setAddress(new Address("city","street","10000"));
        member.setWorkPeriod(new WorkPeriod());
        Member save = repository.save(member);
    }

- member 객체를 테스트 코드에서 만듬

- save 함수 내부에서 begin ~ persist ~ commit 과정을 거침으로써 테스트코드에서는 이에 대한 코드를 작성할 일이 없음

임베디드 타입으로 선언한 값들이 정상적으로 들어오는 것을 알 수 있음

 

 

 

 

 

값 타입 공유 참조

임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험함

 

[ 예시 ]

    @Test
    @Commit
    void insertData() {
        Address address = new Address("city","str","10000");
        //공유 객체

        Member member = new Member();
        member.setName("test");
        member.setPhonenumber("01011");
//        member.setAddress(new Address("city","street","10000"));
        member.setAddress(address);
        member.setWorkPeriod(new WorkPeriod());

        Member member2 = new Member();
        member2.setName("test");
        member2.setPhonenumber("01011");
        member2.setAddress(address);

        member2.getAddress().setCity("geoje"); // 수정

        Member save = repository.save(member);
        Member save2 = repository.save(member2);
    }

 

- address 라는 객체를 공유해서 사용

- member2 에 address 를 수정

- member1 에 address 도 수정됨을 볼 수 있음

 

[ 해결 방법 ]

 

1) 각각의 객체에 new Address 로 생성자를 통해 할당 해줌

member.setAddress(new Address("city","street","10000"));
member2.setAddress(new Address("city2","street2","20000"));

 

2) 불변 객체로 생성

 - setter 부분을 private 로 선언해서 외부에서 수정할 수 없게 만들어주는 방법

+ Recent posts