Free Lines Arrow
본문 바로가기
DataBase/JPA

[JPA] 값타입

by skahn1215 2021. 8. 22.
728x90
반응형

JPA의 데이터 타입

  • JPA의 데이터 분류는 엔티티 타입과 값 타입으로 크게 분류 된다.
  • 값타입은 다양하지만 기본값 타입과 임베디드 타입이 중요하다.

 

 

 

엔티티 타입

  • @Entity 로 정의하는 객체이다.
  • 데이터가 변해도 식별자로 지속해서 추적이 가능하다.

 

 

 

값 타입

  • int, integer, String 처럼 단순히 값으로 사용하는 자바 기본 타입이다.
  • 식별자가 없다.
  • 그렇기 때문에 변경시 추적이 불가하다.

 

 

값타입 분류

1. 기본값 타입

  • 자바 기본 타입(int, double)
  • 래퍼 클래스(Integer, Long)
  • String
  • 생명주기를 엔티티에 의존한다.
  • 회원을 삭제하면 String name등 같이 삭제된다.

 

2. 임베디드 타입

  • 복합값 타입
  • 새로운 값 타입을 직접 정의할 수 있다.
  • 기본 생성자가 필수이다.

 

3. 컬렉션 값 타입

 

 

 

임베디드 타입

새로운 값 타입을 직접정의할 수 있다.

JPA는 임베디드 타입이라한다.

주로 기본 값 타입을 모아 복합값 타입이라고도 한다.

 

 

 

예제

  • 회원엔티티는 다음과 같은 정보를 가진다.
  • 이름, 근무시작일, 근무종료일, 주소 도시, 주소 번지, 주소 우편번호

  • 기존 멤버엔티티가 너무 복잡하니 다음과 같이 정리를 해준다.
  • startDate, endDate 를 Period 임베디드 타입으로 만든다.
  • city, street, zipcode를 address 임베디드 타입으로만든다.

 

다음과 같이 간편해졌다.

 

 

 

 

임베디드 타입 사용법

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

 

코드

Address

@Embeddable
public class Address {
    private String city;
    private String street;
    private String zipcode;

    // 기본생성자는 필수 이다.
    public Address() {
    }

    public Address(String city, String street, String zipCode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipCode;
    }
}

 

Period

@Embeddable
public class Period {
    // 기본생성자는 필수이다.
    public Period() {
    }

    public Period(LocalDateTime startDate, LocalDateTime endDate) {
        this.startDate = startDate;
        this.endDate = endDate;
    }

    private LocalDateTime startDate;
    private LocalDateTime endDate;
}

 

member

@Entity
public class Member extends BaseEntity {

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(length = 10)
    private String name;

    @Embedded
    private Period workPeriod;

    @Embedded
    private Address homeAddress;
}

 

 

임베디드 타입의 장점

  • 재사용
  • 높은 응집도
  • Period.isWork() 처럼 의미있는 메소드를 만들수 있다.

 

 

 

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

  • 임베디드 타입은 엔티티의 값일 뿐이다.
  • 임베디드 타입을 사용하기 전과 후에는 매핑하는 테이블은 같다.
  • 잘설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.

 

 

 

임베디드 타입과 연관관계

  • 임베디드 타입은 임베디드 타입을 가질수 있다.
  • 임베디드 타입은 엔티티를 가질수 있다.

 

 

 

임베디드 타입중복사용

  • 만약 주소를 집주소, 회사주소 두개가 필요 하다면
  • 다음과 같이 임베디드 타입을 두번 선언하면 된다.
  • 하지만 에러가 발생한다.
    - 동일한 컬럼값이 중복 정의가 되었기 때문이다.

 

 

 

임베디드 타입의 중복사용 문제해결방법

두개의 속성을 사용하면 해결된다.

단순하게 컬럼명을 변경해 주는것이다.

  • @AttributeOverrides
  • @AttributeOverride 

 

 

코드

@Entity
public class Member extends BaseEntity {

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(length = 10)
    private String name;

    @Embedded
    private Period workPeriod;

   @Embedded
   private Address homeAddress;

    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name="city",
                    column=@Column(name="WORK_CITY")),
            @AttributeOverride(name="street",
                    column=@Column(name="WORK_STREET")),
            @AttributeOverride(name="zipcode",
                    column=@Column(name="WORK_ZIPCODE"))
    })
    private Address workAddress;

}

 

 

 

값 타입과 불변객체

  • 값타입은 복잡한 객체세상을 단순화 하려고 한다.

 

 

값타입 공유 참조

  • 임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험함 부작용 발생

 

 

값타입 공유예제

  • 회원1과 회원2가 임베디드 타입으로 CIty를 가지고 있을 경우를 생각해보자
  • 만약 City 를 newCity로 변경하면? 회원1 과 회원2 모두 값이 변경이 된다.
  • 그렇기 때문에 값타입을 공유하지 말고 값을 복사해서 사용해야 된다.
  • 그래도 사이드이펙트가 발생할수 있다.

 

Address address = new Address("city","street","10000");

Member member1 = new Member();
member1.setUserName("member1");
member1.setHomeAddress(address);
em.persist(member1);

Member member2 = new Member();
member2.setUserName("member2");
member2.setHomeAddress(address);
em.persist(member2);

 

잘못된 예

// 첫번째 멤버의 주소만 newCity로 변경하고 싶다.
// 둘다 바뀐다.
member1.getHomeAddress().setCity("newCity");​

 

복사해서 저장한예

// 값을 복사해서 해결해준다.
Address copyAddress = new Address(address.getCity(),address.getStreet(), address.getZipCode());
member1.setHomeAddress(copyAddress);
member1.getHomeAddress().setCity("newCity");

 

 

 

복사해도 사이드이펙트카 발생하는경우

  • 누군가 실수로 복사로 안하고 쓰면 역시 사이드이펙트가 발생한다.
  • 막을수 있는 방법이 없다.

 

 

불변객체로만든다.

  • 처음부터 Address 의 값을 변경하지 못하게 setter를 다 지운다.

 

 

값타입의 비교

  • 인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야된다.
  • 값타입은 동등성 비교를 해야된다.
  • 아래예제는 false 가 뜬다.
 Address address1 = new Address("city","street","10000");
 Address address2 = new Address("city","street","10000");
 
 // false 출력
System.out.println("address1 == address2: " + (address1==address2));
System.out.println("address1 == address2: " + address1.equals(address2));

 

equals 와 hashcode 를 오버라이딩 해준다.

public class Address {
    private String city;
    private String street;
    private String zipcode;

    // 기본생성자는 필수 이다.
    public Address() {
    }

    public Address(String city, String street, String zipCode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipCode;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getZipCode() {
        return zipcode;
    }

    public void setZipCode(String zipCode) {
        this.zipcode = zipCode;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return Objects.equals(city, address.city) &&
                Objects.equals(street, address.street) &&
                Objects.equals(zipcode, address.zipcode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(city, street, zipcode);
    }
}

 

 

equals, hashcode 의 사용이유와 예제

https://vprog1215.tistory.com/204?category=989394 

 

[Java] HashMap, hashCode(), equals()

HashMap HashMap 이 어떻게 동작하고 저장하는지 알아본다. HashMap 에서 어떻게 비교연산이 이루어 지는지 알아본다. equals 와 hashCode 함수에 대해 알아본다 HashMap? HashMap 이란 키와 값을 묶어서 하나의.

vprog1215.tistory.com

 

 

 

 

 

 

참고: https://www.inflearn.com/course/ORM-JPA-Basic/lecture/21713?tab=curriculum 

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 학습 페이지

지식을 나누면 반드시 나에게 돌아옵니다. 인프런을 통해 나의 지식에 가치를 부여하세요....

www.inflearn.com

 

728x90
반응형

'DataBase > JPA' 카테고리의 다른 글

[JPA] JPQL 이란?  (0) 2021.09.23
[JPA] 값타입 컬렉션  (0) 2021.09.17
[JPA] CASCADE  (0) 2021.08.22
[JPA] Lazy 와 Eager  (0) 2021.08.19
[JPA] 프록시  (0) 2021.08.11

댓글