@Embeddable
: 값 타입을 정의하는 곳에 표시@Embedded
: 값 타입을 사용하는 곳에 표시@Entity
@Table(name = "MEMBERS")
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
////////////////////////////////// 임베디드 타입
@Embedded
private Period period;
@Embedded
private Address address;
//////////////////////////////////
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
public Team getTeam() {
return team;
}
}
@Entity
@Table(name = "MEMBERS")
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
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;
////////////////////////////////////////////////////
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
}
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("shop");
EntityManager em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try {
Address address = new Address("city", "street", "10000");
Member member1 = new Member();
member1.setName("member1");
member1.setHomeAddress(address);
em.persist(member1);
//////////////////////////////////////////////// 새로 만들기(불변 객체, 값을 복사하는 것은 기본값의 경우 문제가 없으나 참조값의 경우 문제가 발생(공유 참조))
Address newAddress = new Address("NewCity", address.getStreet(), address.getZipcode());
////////////////////////////////////////////////
Member member2 = new Member();
member2.setName("member2");
member2.setHomeAddress(newAddress);
em.persist(member2);
et.commit();
} catch (Exception e) {
et.rollback();
} finally {
em.close();
}
emf.close();
}
}
==
사용==
비교의 경우에는 참조 값을 기준으로 하기 때문에 인스턴스 값이 같다 하더라도 False가 나오게 됨equals()
메서드의 경우 역시 기본적으로 ==
비교이기 때문에 인스턴스의 참조 값을 기준으로 비교를 한다.equals()
사용동등성 비교
를 해야 한다.equals()
메서드를 적절하게 재정의하는 것이 필요하다.@ElementCollection
, @CollectionTable
사용@Entity
@Table(name = "MEMBERS")
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
@Embedded
private Period workPeriod;
@Embedded
private Address homeAddress;
////////////////////////////////////////////////////////////////////
@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<>();
////////////////////////////////////////////////////////////////////
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
// Getter/Setter ...
}
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("shop");
EntityManager em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try {
Member member = new Member();
member.setName("member1");
member.setHomeAddress(new Address("city", "street", "10000"));
///////////////////////////////////////////////////////////////
// 컬렉션 add() 메서드
member.getFavoriteFoods().add("치킨");
member.getFavoriteFoods().add("족발");
member.getFavoriteFoods().add("피자");
member.getAddressHistory().add(new Address("old1", "street", "10000"));
member.getAddressHistory().add(new Address("old2", "street", "10000"));
///////////////////////////////////////////////////////////////
em.persist(member);
et.commit();
} catch (Exception e) {
et.rollback();
} finally {
em.close();
}
emf.close();
}
}
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
try {
Member member = new Member();
member.getAddressHistory().add(new Address("서울특별시", "노원구", "공릉동"));
member.getFavoriteFoods().add("교촌치킨");
member.getFavoriteFoods().add("지코바");
em.persist(member);
em.flush();
em.clear();
Member findMember = em.find(Member.class, member.getId());
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
em.close();
}
emf.close();
}
}
실행 결과
Hibernate:
select
m1_0.MEMBER_ID,
m1_0.city,
m1_0.street,
m1_0.zipcode,
m1_0.name,
m1_0.TEAM_ID,
m1_0.endDate,
m1_0.startDate
from
MEMBERS m1_0
where
m1_0.MEMBER_ID=?
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("shop");
EntityManager em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try {
Member member = new Member();
member.setName("member1");
member.setHomeAddress(new Address("city", "street", "10000"));
member.getFavoriteFoods().add("치킨");
member.getFavoriteFoods().add("족발");
member.getFavoriteFoods().add("피자");
member.getAddressHistory().add(new Address("old1", "street", "10000"));
member.getAddressHistory().add(new Address("old2", "street", "10000"));
em.persist(member);
em.flush();
em.clear();
///////////////////////////////////////////////////////////////
Member findMember = em.find(Member.class, member.getId());
findMember.setHomeAddress(new Address("NewCity", "NewStreet", "20000"));
// remove() 후 add()
findMember.getFavoriteFoods().remove("치킨");
findMember.getFavoriteFoods().add("한식");
// equals() 메서드는 기본적으로 인스턴스의 참조값을 기준으로 비교
// equals() 메서드를 재정의하지않는다면 이렇게 작성해도 삭제가 안 된다.
// 따라서 equals() 메서드를 재정의해서 사용해야하며 역시 remove() 후 add()
findMember.getAddressHistory().remove(new Address("old1", "street", "10000"));
findMember.getAddressHistory().add(new Address("new1", "street", "10000"));
///////////////////////////////////////////////////////////////
et.commit();
} catch (Exception e) {
et.rollback();
} finally {
em.close();
}
emf.close();
}
}
@Entity
@Table(name = "MEMBERS")
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
@Embedded
private Period workPeriod;
@Embedded
private Address homeAddress;
@ElementCollection
@CollectionTable(name = "FAVORITE_FOOD", joinColumns = @JoinColumn(name = "MEMBER_ID"))
@Column(name = "FOOD_NAME")
private Set<String> favoriteFoods = new HashSet<>();
//////////////////////////////////////////////////////////////// 일대다 단방향으로... 일(1)이 연관관계의 주인 → UPDATE 쿼리 호출됨
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "MEMBER_ID")
private List<AddressEntity> addressHistory = new ArrayList<>();
////////////////////////////////////////////////////////////////
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
// Getter/Setter ...
}
@Entity
@Table(name = "ADDRESS")
public class AddressEntity {
@Id @GeneratedValue
private Long id;
@Embedded private Address address;
public AddressEntity(String city, String street, String number) {
this.address = new Address(city, street, number);
}
public AddressEntity() {
}
// Getter/Setter
}
✔️Address 클래스(@Embeddable)
@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;
}
// 값 타입 → 인스턴스의 값을 기준으로 비교(equals() 메서드 재정의 필수)
@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);
}
// 값 타입 → 인스턴스의 값을 기준으로 비교(hashCode() 메서드 재정의 필수)
@Override
public int hashCode() {
return Objects.hash(city, street, zipcode);
}
}
@Entity
@Table(name = "MEMBERS")
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
@Embedded
private Period workPeriod;
@Embedded
private Address Address;
// ...
}
@Entity
public class Delivery extends BaseEntity {
@Id @GeneratedValue
private Long id;
@OneToOne(mappedBy = "delivery", fetch = FetchType.LAZY)
private Order order;
@Embedded
private Address address;
private DeliveryStatus status;
// ...
}