[SpringBoot-JPA 기본편] 자바 ORM 표준 JPA 프로그래밍 - 기본편: 9. 값 타입
강의 출처:
https://www.inflearn.com/course/ORM-JPA-Basic#curriculum
자바 ORM 표준 JPA 프로그래밍 - 기본편 강의 - 인프런
저는 야생형이 아니라 학자형인가봐요^^ 활용편 넘어갔다 30% 정도 듣고 도저히 답답해서 기본편을 들어버렸네요^^. 한주 한주 김영한님 강의 들으니 렙업되는 모습을 스스로 느낍니다. 특히 실
www.inflearn.com
해당 강의는 Inflearn에 등록된 김영한님의 Spring Boot 강의입니다.
jpa는 크게 2가지 타입으로 나뉜다. 엔티티 타입 vs 값 타입
엔티티 타입은 지금까지 배운 타입이고, 이번 시간에는 값 타입을 공부하자.
1. 기본값 타입
값 타입 분류
다음과 같이 패키지를 하나 만들어서 각 클래스를 추가하자.
여기서 중요하게 봐야할 것은 임베디드 타입은 반드시 기본 생성자
를 만들어야 한다.
MemberEmbeded
객체
@Entity
public class MemberEmbeded {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
//임베디드 타입으로 매핑 하는 이유
@Embedded
//기간
private Period workPeriod;
//★★★한개의 엔티티를 두개로 사용하는법:@AttributeOverride★★★
@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;
다음과 같이 임베디드 타입
으로 각 객체 workPeriod
와 homeAddress
를 생성하였다.
이때 workAddress는 속성을 일일이 정의하였다. 이로 인해 회원의 집주소와 회사 주소를 명시할 수 있게 되었다. 이로 인해 같은 값 타입을 불러와서 써도 컬럼명의 중복을 방지 할 수 있게 되었다.
Period
객체
//내장형이다.
@Embeddable
public class Period {
//기간 Period
private LocalDateTime startDate;
private LocalDateTime endDate;
public Period() {
}
//getter,setter
}
Address
객체
//내장형이다.
@Embeddable
public class Address {
//w주소
private String city;
private String street;
private String zipcode;
//기본 생성자
public Address() {
}
//생성자를 통해 setting (생성자 주입)
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
//getter,setter
}
임베디드 타입의 장점은 다음과 같다.
상속하는게 아니라 다른 엔티티에 삽입하기가 좋다. 재사용성을 높인다.
main
함수에서 MemberEmbeded
값 setting
MemberEmbeded memberEmbeded= new MemberEmbeded();
memberEmbeded.setName("chochanguk");
memberEmbeded.setHomeAddress(new Address("서울","낙성대역 8길","10"));
memberEmbeded.setWorkPeriod(new Period());
em.persist(memberEmbeded);
결과
2. 값 타입 컬렉션
Adress
를 객체로 사용하는 AddressEntity
생성
@Entity
@Table(name = "ADDRESS")
public class AddressEntity {
@Id
@GeneratedValue
private Long id;
private Address address;
public AddressEntity() {
}
public AddressEntity(String city, String street, String zipcode) {
this.address = new Address(city, street, zipcode);
}
//getter,setter
}
MemberEmbeded
에 값타입 컬렉션 추가( getter,setter 재설정)
//★★★값 타입 컬렉션★★★
@ElementCollection
@CollectionTable(name = "FAVORITE_FOOD", joinColumns =
@JoinColumn(name = "MEMBER_ID")
)
@Column(name = "FOOD_NAME")
private Set<String> favoriteFoods = new HashSet<>();
//값 타입 매핑하기
// @ElementCollection
// @CollectionTable(name = "ADDRESS", joinColumns =
// @JoinColumn(name = "MEMBER_ID")
// )
// private List<Address> addressHistory = new ArrayList<>();
//★★★★일대다로 매핑하는게 쿼리 최적화에 더 좋고, 할 수 있는게 많아진다.
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "MEMBER_ID")
private List<AddressEntity> addressList = new ArrayList<>();
//getter,setter 재설정
main
함수에서 값 타입 조회 및 값 타입 컬렉션 수정 예제
MemberEmbeded memberEmbeded1 = new MemberEmbeded();
//생성자로 입력해서 세팅하기
memberEmbeded1.setHomeAddress(new Address("homeCity", "낙성대역 8길", "10"));
//좋아하는 음식의 set을 가져와서 추가하기(세팅)
memberEmbeded1.getFavoriteFoods().add("치킨");
memberEmbeded1.getFavoriteFoods().add("치킨");
memberEmbeded1.getFavoriteFoods().add("피자");
memberEmbeded1.getAddressHistory().add(new AddressEntity("old1", "낙성대역 8길", "10000"));
memberEmbeded1.getAddressHistory().add(new AddressEntity("old2", "낙성대역 8길", "10000"));
em.persist(memberEmbeded1); //member만 persist하기
em.flush();
em.clear();
//★★ 값 타입 조회 하기 에제★★
System.out.println("=====================");
MemberEmbeded findMember = em.find(MemberEmbeded.class, memberEmbeded1.getId()); //
//addressHistoryList 조회
List<AddressEntity> addressHistoryList = findMember.getAddressHistory();
for (AddressEntity address : addressHistoryList) {
System.out.println("address = " + address.getAddress().getCity());
}
//favoriteFoods 조회 하기
Set<String> favoriteFoods = findMember.getFavoriteFoods();
for (String favoriteFood : favoriteFoods) {
System.out.println(" favorite foods = " + favoriteFood);
}
//★★★★ 값 타입 수정하기 예제 ★★★★
System.out.println("=========START========");
MemberEmbeded findMemberForReset = em.find(MemberEmbeded.class, memberEmbeded1.getId());
//이건 잘못된 방식
//findMemberForReset.getHomeAddress().setCity("new CITY");
//값타입을 이게 제대로 된 방식(UPDATE 쿼리가 나감)
Address old = findMemberForReset.getHomeAddress();
findMemberForReset.setHomeAddress(new Address("new City", old.getStreet(), old.getZipcode()));
//★★★값 타입 컬렉션을 수정하는 법★★★
findMemberForReset.getFavoriteFoods().remove("치킨");
findMemberForReset.getFavoriteFoods().add("한식");
//★★★값 타입 컬렉션을 수정하는 법2★★★
findMemberForReset.getAddressHistory().remove(new AddressEntity("old1", "낙성대역 8길", "10"));
findMemberForReset.getAddressHistory().add(new AddressEntity("new City", "낙성대역 8길", "10"));
결과