Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

Embedded 본문

JPA/Embedded

Embedded

Seung__ 2021. 7. 10. 20:37

Embedded 타입이란? 값 타입의 일종으로 복합 타입으로 이해하면 된다.

 

여러개의 값을 모아서 하나의 값으로 사용함.

- ex) (x, y) -> point

 

값 타입이란 값 타입은 int, Integer, String과 같이 값을 가지고 있는 타입들이 속한다.

 

Embedded type은 여러개의 값을 묶어서 하나의 으로 만들 수 있다.

 

embedded된 객체를 하나의 값으로 인식하자.

 

embedded된 객체를 활용하여 좀 더 객체 지향적, 깔끔한 코드를 작성이 가능하다.

 

 

 

1. embedded type없이


 

User class에 주소를 추해주자.

private String city;
private String district;
private String detail;
private String zipCode;

 entity, db column이라고 해서...field를 막 선언하는게 맞나..?

 

*dry:  don't repeat yourself에 위반된다. 코드는 복붙을 지양하고 객체화해서 사용해야 한다.

 

여기서 사용되는 개념이 embedded type이다.

 

2. embedded로 변환


주소를 객체화해서 사용하자. 

<Address class> Embeddasble class로 명시하기 위해 @Embeddable annotation을 붙여준다.

@Embeddable
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {


    private String city;    //시
    
    private String district;//구

    @Column(name = "address_detail")
    private String detail;  //상세주소
    
    private String zipCode; //우편번호


}

 

그리고 address객체를 사용하는 User class에서는 Address객체에 @Embedded 명기해준다.

 @Embedded
 private Address address;

embedded된 객체를 사용해서 이전에 봤던 세부 사항들이 Address로 처리가 된다.

 

코드가 더욱 객체지향적, 깔끔해진다.

 

* @Embeddable : embedded화 할 class에 표시

 

* @Embedded : embedded된 객체를 사용하는 곳에 표시.

 

 

<Test>

@Test
void embeddedTest(){

  userRepository.findAll().forEach(System.out::println);

  User user = new User();
  user.setName("hyun");
  user.setAddress(new Address("서울시", "송파구", "송파대로", "0000"));
  
  userRepository.save(user);
  
  userRepository.findAll().forEach(System.out::println);
}

 

user table생성을 보면 주소에 관련된 columns이 생성되었고,

 

user 생성 후 입력한 주소가 잘 반영되어있다.

 

Hibernate: 
    
    create table user (
       id bigint not null auto_increment,
        created_at datetime(6) default now(6) comment '생성시간' not null,
        updated_at datetime(6) default now(6) comment '수정시간' not null,
        city varchar(255),
        address_detail varchar(255),
        district varchar(255),
        zip_code varchar(255),
        email varchar(255),
        gender varchar(255),
        name varchar(255),
        primary key (id)
    ) engine=InnoDB

User(super=BaseEntity(createdAt=2021-07-10T19:12:41, updatedAt=2021-07-10T19:12:41), 
	name=hyun, email=hyun@naver.com, id=1, testData=null, gender=null, address=null)
User(super=BaseEntity(createdAt=2021-07-10T19:12:41, updatedAt=2021-07-10T19:12:41), 
	name=park, email=park@google.com, id=2, testData=null, gender=null, address=null)
User(super=BaseEntity(createdAt=2021-07-10T19:12:41, updatedAt=2021-07-10T19:12:41), 
	name=lee, email=lee@naver.com, id=3, testData=null, gender=null, address=null)
User(super=BaseEntity(createdAt=2021-07-10T19:12:41, updatedAt=2021-07-10T19:12:41), 
	name=kim, email=kim@google.com, id=4, testData=null, gender=null, address=null)
User(super=BaseEntity(createdAt=2021-07-10T19:12:41, updatedAt=2021-07-10T19:12:41), 
	name=hyun, email=hyun@google.com, id=5, testData=null, gender=null, address=null)
User(super=BaseEntity(createdAt=2021-07-10T19:12:44.738212300, updatedAt=2021-07-10T19:12:44.738212300),
	name=hyun, email=null, id=6, testData=null, gender=null, address=Address(city=서울시, district=송파구, detail=송파대로, zipCode=0000))

 

 

 

3. @AttributeOverride 


Embeddable class를 한 객체에서 재활용 할 경우 table 생성 시 column명이 중복된다.

 

따라서 column명이 table에서 중복되지 않게  column 명 지정이 필요하다.

 

해당 기능을 제공하는 annotation이 @AttributeOverride이다.

 

@AttributeOverriedes의 하위에 @AttributeOverride의 배열로 넣어준다.

 

@AttibuteOvverides(
{
 @AttributeOverride(name = "field - 1", column = @Column(name = "table -1")),
 @AttributeOverride(name = "field - 2", column = @Column(name = "table -2")),
 @AttributeOverride(name = "field - 3", column = @Column(name = "table -3"))
})

 

예를들어 user정보에 집주소, 직장주소 둘다 넣고싶어서 Address를 재활용했다고 해보자.

 

<user class>

    @Embedded
    private Address homeAddress;

    @Embedded
    private Address companyAdress;

하지만 이렇게되면 user table에 Address와 관련된 column이 2개 씩 존재하게된다.

 

기본적으로 DB에서 한 table에서  column명 중복을 허용하지 않는다.

 

 

   @Embedded
    @AttributeOverrides(
            {@AttributeOverride(name = "city", column = @Column(name = "home_city")),
            @AttributeOverride(name = "district", column = @Column(name = "home_district")),
            @AttributeOverride(name = "detail", column = @Column(name = "home_address_detail")),
            @AttributeOverride(name = "zipCode", column = @Column(name = "home_zip_code"))}
    )
    private Address homeAddress;

    @Embedded
    @AttributeOverrides(
            {@AttributeOverride(name = "city", column = @Column(name = "company_city")),
                    @AttributeOverride(name = "district", column = @Column(name = "company_district")),
                    @AttributeOverride(name = "detail", column = @Column(name = "company_address_detail")),
                    @AttributeOverride(name = "zipCode", column = @Column(name = "company_zip_code"))}
    )
    private Address companyAdress;

 

table에 home address와 company address가 별도 column으로 생성되었고,

user entity에도 잘 입력되어있다.

 

Hibernate: 
    
    create table user (
       id bigint not null auto_increment,
        created_at datetime(6) default now(6) comment '생성시간' not null,
        updated_at datetime(6) default now(6) comment '수정시간' not null,
        company_city varchar(255),
        company_address_detail varchar(255),
        company_district varchar(255),
        company_zip_code varchar(255),
        email varchar(255),
        gender varchar(255),
        home_city varchar(255),
        home_address_detail varchar(255),
        home_district varchar(255),
        home_zip_code varchar(255),
        name varchar(255),
        primary key (id)
    ) engine=InnoDB
    
    User(super=BaseEntity(createdAt=2021-07-10T19:29:44.182866200, updatedAt=2021-07-10T19:29:44.182866200), 
      name=hyun, email=null, id=6, testData=null, gender=null, 
      homeAddress=Address(city=서울시, district=송파구, detail=송파대로, zipCode=0000), 
      companyAdress=Address(city=서울시, district=강남구, detail=강남대로, zipCode=0000))

 

 

 

4. Null이들어간다?


만약 Address에서 null point exception이 발생한다면 두 가지중 하나일 것이다.

 

setAddress(null) : null이 들어가거나 또는 setAddress(new Address()) : 빈 Address 객체가 들어가거나

 

<Test>

 User user1 = new User();
 user1.setName("bababa");
 user1.setHomeAddress(null);
 user1.setCompanyAdress(null);

userRepository.save(user1);

User user2 = new User();
user2.setName("AAAAA");
user2.setHomeAddress(new Address());
user2.setCompanyAdress(new Address());

userRepository.save(user2);

 

setAddress(null)인 경우는 Address조회시 null이 반환된다.

 

반면에 빈 Address객체의 경우 하위 각 항목이 null로 return된다.

User(super=BaseEntity(createdAt=2021-07-10T19:43:36.263778100, updatedAt=2021-07-10T19:43:36.263778100), name=bababa, email=null, id=7, testData=null, gender=null, 
homeAddress=null, 
companyAdress=null)
User(super=BaseEntity(createdAt=2021-07-10T19:43:36.275453800, updatedAt=2021-07-10T19:43:36.275453800), name=AAAAA, email=null, id=8, testData=null, gender=null, 
homeAddress=Address(city=null, district=null, detail=null, zipCode=null), 
companyAdress=Address(city=null, district=null, detail=null, zipCode=null))

native query를 통해 DB에 저장된 값을 확인해보자.

[7, 2021-07-10 19:48:53.331188, 2021-07-10 19:48:53.331188, null, null, null, null, null, null, null, null, null, null, bababa]
[8, 2021-07-10 19:48:53.339141, 2021-07-10 19:48:53.339141, null, null, null, null, null, null, null, null, null, null, AAAAA]

둘 다 address는 null인데 출력된 형식이 다르다.

 

왜 다를까? --> cache때문이다!

 

 

Entity Cache

https://github.com/bsh6463/BookManager bsh6463/BookManager Contribute to bsh6463/BookManager development by creating an account on GitHub. github.com 1. Entity Manager Entity Manager란?  Entity의..

bsh-developer.tistory.com

findAll()전 entitymanger를 clear하여 cache를 삭제해보자.

 

cache를 삭제했으니 DB에서 값을 읽어올 것이다.

 

짠 둘다 동일한 형식으로 출력되었다.

User(super=BaseEntity(createdAt=2021-07-10T19:51:43.602783, updatedAt=2021-07-10T19:51:43.602783), name=bababa, email=null, id=7, testData=null, gender=null,
homeAddress=null, companyAdress=null)
User(super=BaseEntity(createdAt=2021-07-10T19:51:43.610638, updatedAt=2021-07-10T19:51:43.610638), name=AAAAA, email=null, id=8, testData=null, gender=null, 
homeAddress=null, companyAdress=null)

 

즉 embedded된 객체가 null인 경우 내부 column이 모두 null인 경우와 동일하다

 

 

 

5. GitHub : 210710 Imbedded Type


 

bsh6463/BookManager

Contribute to bsh6463/BookManager development by creating an account on GitHub.

github.com

 

Comments