@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
// 1 대 N이며 team에 의해서 관리되고 있다는 것을 의미하기에 연관관계 주인은 team이라는 것을 의미하며
// members에 값을 넣어도 아무 관계가 벌어지지 않으며 team에서 모든 수정 작업이 이뤄진다. 값을 변경시에 team만을 참조한다.
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
-----------------------------------------------------------------------------------------
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
// @Column(name = "TEAM_ID")
// private Long teamId;
@Column(name = "USERNAME")
private String username;
// 하나의 Team에 여러명의 Member가 포함이 되므로 1 : N의 관계
@ManyToOne
// 연결해야 하는 columns의 값의 명 기입
// JoinColumn으로 매핑을 함 관리를 한다를 의미
@JoinColumn(name = "TEAM_ID")
private Team team;
-----------------------------------------------------------------------------------------
객체 지향적이지 않은 코드
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
----------------------------------------------------------------------------------------
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
----------------------------------------------------------------------------------------
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setUsername("member1");
member.setTeamId(1L);
em.persist(member);
tx.commit();
----------------------------------------------------------------------------------------
이 방법의 경우 외래키를 참조 하는 것이 아닌 직접 값을 들고오는 형식을 가지게 된다.
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
// @Column(name = "TEAM_ID")
// private Long teamId;
@Column(name = "USERNAME")
private String username;
// 하나의 Team에 여러명의 Member가 포함이 되므로 1 : N의 관계
@ManyToOne
// 연결해야 하는 columns의 값의 명 기입
@JoinColumn(name = "TEAM_ID")
private Team team;
----------------------------------------------------------------------
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
----------------------------------------------------------------------
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setUsername("member1");
member.setTeam(team);
em.persist(member);
tx.commit();
----------------------------------------------------------------------
이 같은 경우는 단방향으로 맴버에서 팀으로 이동이 가능하지만 팀에서 맴베로 이동이 불가능하다.
양방향 매핑
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
// mappedBy =
@OneToMany(mappedBy = "team")
// ArrayList초기화를 방지하기 위해서 선언
private List<Member> members = new ArrayList<Member>();
---------------------------------------------------------------------------------------------
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
// @Column(name = "TEAM_ID")
// private Long teamId;
@Column(name = "USERNAME")
private String username;
// 하나의 Team에 여러명의 Member가 포함이 되므로 1 : N의 관계
@ManyToOne
// 연결해야 하는 columns의 값의 명 기입
@JoinColumn(name = "TEAM_ID")
private Team team;
---------------------------------------------------------------------------------------------
Member findMember = em.find(Member.class, member.getId());
List<Member> members = findMember.getTeam().getMembers();
for (Member m : members){
System.out.println(m.getUsername());
}
---------------------------------------------------------------------------------------------
- MEMBER의 team값을 바꿨을 때 외래키 값이 업데이트 되어야 하는지 Team의 members을 업데이트 했을때인지 생각하게 된다.
- 그렇기에 둘 중 하나로 양방향 매핑에서 연관관계의 주인을 정하게 된다.
mappedBy : 어떤 것에 의해서 매핑이 되었다를 의미
- OneToMany에 해당하는 1에 해당하는 Class에 mappedBy를 걸게 한다.
- List members의 값은 읽기만 가능한 값이다.
- 외래키가 있는 곳을 주인으로 정해야 하며 DB의 관점에서 보게 된다면 외래키가 있는 곳이 N에 해당하게 된다.
- 자동차에 비유했을 때 차와 바퀴가 있을 경우 바퀴가 연관관계의 주인이 되어야 한다.(설계부분이나 성능 이슈를 해결하게 되며 왜래키와 Entity를 한꺼번에 관리를 할 수 있다.)
Member member = new Member();
member.setUsername("member1");
em.persist(member);
Team team = new Team();
team.setName("TeamA");
team.getMembers().add(member);
em.persist(team);
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setUsername("member1");
member.setTeam(team);
em.persist(member);
양 방향 매핑의 값을 양쪽 다 넣어줘야 하며 이 같은 방법은 2가지 정도가 있다.
team에 member의 값을 넣는 방법
1.
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setUsername("member1");
em.persist(member);
team.addMember(member);
----------------------------------------------------------------------------------
public void addMember(Member member){
member.setTeam(this);
members.add(member);
}
----------------------------------------------------------------------------------
member에 team의 값을 넣는 방법
2.
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setUsername("member1");
member.changeTeam(team);
em.persist(member);
----------------------------------------------------------------------------------
public void changeTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
하지만 한 부분에 값을 넣어야 하며 두 공간 모두에 값을 넣어주는 방법을 택한다면 무한 루프에 빠지는 경우가 생길 수도 있다.
- 처음 설계시에는 단방향 매핑으로 설계를 시작한다.
- 양방향 매핑같은 경우 역방향의 참조를 하게 되는 경우에 필요하다.
- 단방향을 설계해둔 경우 양방향 매핑 같은 경우 필요시 추가하면 된다.
- 예를 들어 지금까지의 코드 내용을 보게 된다면 Team 안에 ListMember만 추가 하게 된다면 양방향으로 바뀌었던 것처럼 단방향 매핑이 끝난 경우 양방향 전환을 할 때 양방향 매핑시 테이블을 건드리지 않는다.
package jpabook.jpashop.domain;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "ORDERS")
public class Order {
@Id
@GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
// order_id와 매핑된 것이 orderitem의 order이기에
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems = new ArrayList<>();
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
public void addOrderItem(OrderItem orderItem){
orderItems.add(orderItem);
orderItem.setOrder(this);
}
public Long getId() {
return id;
}
public Member getMember() {
return member;
}
public void setMember(Member member) {
this.member = member;
}
public void setId(Long id) {
this.id = id;
}
public LocalDateTime getOrderDate() {
return orderDate;
}
public void setOrderDate(LocalDateTime orderDate) {
this.orderDate = orderDate;
}
public OrderStatus getStatus() {
return status;
}
public void setStatus(OrderStatus status) {
this.status = status;
}
}
------------------------------------------------------------------------------
package jpabook.jpashop.domain;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Member {
@Id
@GeneratedValue()
@Column(name = "MEMBER_ID")
private Long id;
private String name;
private String city;
private String street;
private String zipcode;
// 비즈니스상 아래의 코드는 없는 것이 더 좋은 관계이다.
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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;
}
}
------------------------------------------------------------------------------
package jpabook.jpashop.domain;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// DB의 커넥션을 하나 얻은 것이다.
EntityManager em = emf.createEntityManager();
// Transaction 시작
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Order order = new Order();
em.persist(order);
OrderItem orderItem = new OrderItem();
orderItem.setOrder(order);
em.persist(orderItem);
tx.commit();
} catch (Exception e){
tx.rollback();
} finally {
// EntityManager가 DB커넥션을 물고 동작하기에 사용을 하고 닫아줘야 한다.
em.close();
}
emf.close();
}
}
------------------------------------------------------------------------------
package jpabook.jpashop.domain;
import javax.persistence.*;
@Entity
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "ORDER_ITEM_ID")
private Long id;
@ManyToOne
@JoinColumn(name = "ORDER_ID")
private Order order;
@ManyToOne
@JoinColumn(name = "ITEM_ID")
private Item item;
private int orderPrice;
private int count;
public Long getId() {
return id;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public void setId(Long id) {
this.id = id;
}
public int getOrderPrice() {
return orderPrice;
}
public void setOrderPrice(int orderPrice) {
this.orderPrice = orderPrice;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
------------------------------------------------------------------------------
package jpabook.jpashop.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Item {
@Id
@GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
private int stockQuantity;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getStockQuantity() {
return stockQuantity;
}
public void setStockQuantity(int stockQuantity) {
this.stockQuantity = stockQuantity;
}
}
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
--------------------------------------------------------------------------------
단반향의 설계시
Hibernate:
create table Member (
MEMBER_ID bigint not null,
USERNAME varchar(255),
TEAM_ID bigint,
primary key (MEMBER_ID)
)
Hibernate:
create table Team (
TEAM_ID bigint not null,
name varchar(255),
primary key (TEAM_ID)
)
Hibernate:
alter table Member
add constraint FKl7wsny760hjy6x19kqnduasbm
foreign key (TEAM_ID)
references Team
Hibernate:
call next value for hibernate_sequence
Hibernate:
call next value for hibernate_sequence
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(TEAM_ID, USERNAME, MEMBER_ID)
values
(?, ?, ?)
Hibernate:
/* insert hellojpa.Team
*/ insert
into
Team
(name, TEAM_ID)
values
(?, ?)
8월 23, 2022 3:37:40 오후 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:tcp://localhost/~/test]
종료 코드 0(으)로 완료된 프로세스
'JPA' 카테고리의 다른 글
다양한 연관관계 매핑 (section 6) (0) | 2022.08.23 |
---|---|
엔티티 매핑(section 4) (0) | 2022.08.14 |
영속성 컨텍스트(section 3) (1) | 2022.08.09 |
Transactional(section 2) (0) | 2022.08.05 |
JPA의 소개(section1) (0) | 2022.08.05 |