다대일을 가장 많이 쓰고, 다대다는 실무에서 쓰면 안된다.
관계형 db에서는 '다'쪽에 외래키가 들어가줘야한다.
와래키 있는 쪽 기준으로 거기에다가 연관한 참조를 넣어줘서 매핑을 걸면 된다.
여기서는 '일'쪽이 연관관계의 주인이다.
실무에서 이 모델은 거의 가져가지 않는다.
기본 스펙에 있기 때문에 설명
db에선 무조건 '다'쪽에 외래키가 들어가야한다.
Team의 members를 변경하면 그게 MEMBER의 TEAM_ID를 업데이트 시켜 줘야한다.
Team.java
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<>();
Member.java
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
JpaMain.java
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member = new Member();
member.setUsername("member1");//실무에선 set 안쓰고 빌더패턴을 씀
em.persist(member);
Team team = new Team();
team.setName("teamA");
team.getMembers().add(member);
em.persist(team);
tx.commit();
} catch (Exception e) {
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
Team, Member에 insert쿼리가 나가고 마지막에 update쿼리가 나간다.
테이블 수십개가 돌아가는 실무에선 잘쓰지 않는다.
@OneToMany
//@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<>();
@JoinColumn을 사용하지 않으면,
다음과 같은 TEAM_MEMBER가 생성된다.
Member쪽에서도 team을 보고 싶어.
그럼
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne
@JoinColumn(insertable = false, updatable = false)
private Team team;
매핑이나 설계는 단순해야한다.
JoinColumn 속성 중 name은 넣어줘야 한다. 안 넣으면 기본 값이 지저분 함.
Member.java
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID",insertable = false, updatable = false)
private Team team;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
Locker.java
@Entity
public class Locker {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToOne(mappedBy = "locker")
private Member member;
}
일대일 관계는 '내 엔티티에 있는 외래키를 내가 관리!'
Locker에 member가 있으면 얘를 연관관계 주인으로 잡고, Locker locker는 읽기 전용으로 만들면 된다.
일대일 주 테이블에 외래 키 양방향과 매핑방향은 똑겉다.
주 테이블 : 주로 액세스하는 테이블
실무에서는 쓰면 안된다.
디비는 중간 연결 테이블을 만들어서 풀어내야 한다.
객체는 다대다 관계가 가능하다.
ORM이 객체 그림과 테이블 그림을 매핑해준다.
테이블은 다대다가 안되니까 jointable을 집어넣어서 하는 매핑을 해준다.
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID",insertable = false, updatable = false)
private Team team;
@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT")
private List<Product> products = new ArrayList<>();
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
MEMBER_PRODUCT 테이블이 생성된것을 확인할 수 있다.
단방향을 양방향으로 만들고 싶으면 Product에 가서
@Entity
public class Product {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany(mappedBy = "products")
private List<Member> members = new ArrayList<>();
추가해주자.
중간 테이블엔 매핑 정보만 들어가고 추가 정보는 들어갈 수 없다.
또한 쿼리가 이상하게 나간다. -> 실무에서 쓰지 말자
MemberProduct.java
@Entity
public class MemberProduct {
@Id
@GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
}
Member.java
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProducts = new ArrayList<>();
Product.java
@OneToMany(mappedBy = "product")
private List<MemberProduct> memberProducts = new ArrayList<>();
이제 내가 원하는 걸 마음대로 MemberProduct에 넣을 수 있음.
예제라 MemberProduct로 잡았지만,Orders 같은 의미있는 이름이 붙여지게 됨.
웬만하면 Pk는 비즈니스 적으로 의미없는 값을 써야한다.
Category.java
@Entity
public class Category {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "PARENT_ID")
private Category parent;
@OneToMany(mappedBy = "parent")
private List<Category> child = new ArrayList<>();
@ManyToMany
@JoinTable(name = "CATEGORY_ITEM",
joinColumns = @JoinColumn(name = "CATEGORY_ID"), //내가 조인하는건 얘고
inverseJoinColumns = @JoinColumn(name = "ITEM_ID") //반대쪽인 조인하는건 얘야
)
private List<Item> items = new ArrayList<>();
}
Delivery.java
@Entity
public class Delivery {
@Id@GeneratedValue
private Long id;
private String city;
private String street;
private String zipcode;
private DeliveryStatus status;
@OneToOne(mappedBy = "delivery")
private Order order;
}
Order.java
@Entity
@Table(name = "ORDERS")
public class Order {
@Id
@GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
//@Column(name = "MEMBER_ID")
//private Long memberId;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@OneToOne
@JoinColumn(name = "DELIVERY_ID")
private Delivery delivery;
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems = new ArrayList<>();
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
Item.java
@Entity
public class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long Id;
private String name;
@ManyToMany(mappedBy = "items")
private List<Category> categories = new ArrayList<>();
private int Price;
private int stockQuality;
CATEGORY_ITEM 테이블이 제대로 생성되었다.
ORDERS 테이블에도 delivert가 제대로 들어있는걸 확인할 수 있다.
예시여서 다대다로 해봤는데 실전에선 이렇게 하면 안됨!