関連関係マッピング1-関連関係マッピングタイプ
39569 ワード
ほとんどのエンティティは他のエンティティに関連付けられています.JPAでは、関連付けをエンティティにマッピングし、必要に応じてエンティティに関連付けられたエンティティを使用してオブジェクト向けにプログラミングできます.
🐢
1.関連関係マッピングのタイプ:一対一(1:1)、一対多(1:N)、多対一(N:1)、多対一(N:M)
2.エンティティマッピングの方向性:一方向、双方向
1対1の一方向のマッピング
カート(
アプリケーションを実行すると、コンソールウィンドウでcartテーブルを作成するクエリー文と、外部キーを持つmember id列のクエリー文が表示されます.このような利点は、カートエンティティを参照しながらメンバーエンティティの情報を取得できることです.
実際には、カートエンティティを表示すると、関連するメンバーエンティティがインポートされたかどうかを判断するテストコードを作成します.まず、 上で
これらのエンティティをクエリーする場合、エンティティとマッピングされたエンティティを一度にクエリーすることをインスタント・ロードと呼びます.「1対1」または「複数対1」にマッピングされている場合は、「即時ロード」をデフォルトのFetchポリシーに設定します.
複数対1の一方向のマッピング
1つのショッピングバスケットには複数の商品が収容できます.また、同じ商品を複数注文できるので、いくつかセットするように設定します.ショッピングカートアイテム
マルチペア/ペアマルチ双方向マッピング
デュアルポートマッピングには、2つの一方向マッピングが考えられる.受注と受注商品のマッピングを双方向に設定します.まず、設計は 1人のメンバーは複数回注文できるので、注文エンティティ 受注エンティティはカートエンティティとほぼ同じです.まず、受注エンティティと受注エンティティの一方向マッピングを設定します.関連関係の所有者が外部キー所在地 に設定関連関係の所有者管理(登録、修正、削除) 非所有者関連関係の所有者を関連関係マッピング時のmapperdBy属性の値 に設定マスター以外のページは読み取り専用 OrderItemと関連関係マッピングをOrderエンティティに追加します.関連関係の所有者設定をよく確認してください. 無条件の双方向マッピング関連関係の場合、エンティティは多数のテーブルに関連付けられ、エンティティクラス自体が複雑になるため、関連関係の一方向マッピングとして設計した後、必要に応じて双方向マッピングを追加することをお勧めします.
マルチペアマルチマッピング-Xの使用
多くのJPA書では多対多マッピングについても言及されているが,それらは実際の操作では使用されないマッピング関係である.複数対のマルチマッピングを使用しないのは、カラムを接続テーブルに追加できないためです.「接続」(Connection)テーブルには、通常、追加のカラムと結合カラムが必要です.また、エンティティをクエリーする場合、どのクエリー文が実行されるかを予測するのは難しいです.したがって、マルチマッピングではなく、1対のマルチマッピングに設定できます.
🐢
연관 관계 매핑
をするときは、二つのことを覚えておいてください.太鼓の槌1.関連関係マッピングのタイプ:一対一(1:1)、一対多(1:N)、多対一(N:1)、多対一(N:M)
2.エンティティマッピングの方向性:一方向、双方向
1対1の一方向のマッピング
カート(
Cart
)エンティティを作成し、既存のメンバーエンティティとの関連マッピングを設定します.package me.jincrates.gobook.domain.carts;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import me.jincrates.gobook.domain.members.Member;
import javax.persistence.*;
@NoArgsConstructor
@Getter
@Table(name = "cart")
@Entity
public class Cart {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "cart_id")
private Long id;
@OneToOne
@JoinColumn(name = "member_id")
private Member member;
@Builder
public Cart(Member member) {
this.member = member;
}
}
@JoinColumn
:マッピングする外部キーを指定します.@JoinColumn
のname
が指定されていない場合は、JPAが独自に検索しますが、必要に応じて対応するカラム名を生成できない場合があります.アプリケーションを実行すると、コンソールウィンドウでcartテーブルを作成するクエリー文と、外部キーを持つmember id列のクエリー文が表示されます.このような利点は、カートエンティティを参照しながらメンバーエンティティの情報を取得できることです.
実際には、カートエンティティを表示すると、関連するメンバーエンティティがインポートされたかどうかを判断するテストコードを作成します.まず、
JpaRepository
を継承するCartRepository
インタフェースを作成します.package me.jincrates.gobook.domain.carts;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CartRepository extends JpaRepository<Cart, Long> {
}
package me.jincrates.gobook.domain.carts;
import me.jincrates.gobook.domain.members.Member;
import me.jincrates.gobook.domain.members.MemberRepository;
import me.jincrates.gobook.web.dto.MemberFormDto;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceContext;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
@Transactional
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
public class CartTest {
@Autowired
CartRepository cartRepository;
@Autowired
MemberRepository memberRepository;
@Autowired
PasswordEncoder passwordEncoder;
@PersistenceContext
EntityManager em;
public Member createMember() {
MemberFormDto memberFormDto = MemberFormDto.builder()
.email("[email protected]")
.name("테스트")
.address("서울시 강서구")
.password("1111")
.build();
return Member.createMember(memberFormDto, passwordEncoder);
}
@Test
@DisplayName("장바구니 회원 엔티티 매핑 조회 테스트")
public void findCartAndMemberTest() {
Member member = createMember();
memberRepository.save(member);
Cart cart = Cart.builder()
.member(member)
.build();
cartRepository.save(cart);
em.flush();
em.clear();
Cart savedCart = cartRepository.findById(cart.getId())
.orElseThrow(EntityNotFoundException::new);
assertEquals(savedCart.getMember().getId(), member.getId());
}
}
em.flush()
:JPAは、データを永続コンテキストに格納し、トランザクションの終了時にflush()
を呼び出してデータベースに反映します.上記では、メンバーエンティティとカートエンティティを永続性コンテキストに格納し、엔티티 매니저(em)
強制呼び出しflush()
からデータベースに反映します.em.clear()
:JPAは永続性コンテキストからエンティティを問合せ、永続性コンテキストにエンティティがない場合はデータベースを問合せます.実際のデータベースからカートエンティティをインポートする場合は、永続コンテキストをクリアして、メンバーエンティティも一緒にインポートされるようにします.cartRepository.findById(cart.getId())
コードを実行すると、cartテーブルとmemberテーブルを結合してインポートしたクエリー文が実行されます.cartエンティティを問合せながらメンバーエンティティをインポートします.これらのエンティティをクエリーする場合、エンティティとマッピングされたエンティティを一度にクエリーすることをインスタント・ロードと呼びます.「1対1」または「複数対1」にマッピングされている場合は、「即時ロード」をデフォルトのFetchポリシーに設定します.
複数対1の一方向のマッピング
1つのショッピングバスケットには複数の商品が収容できます.また、同じ商品を複数注文できるので、いくつかセットするように設定します.ショッピングカートアイテム
CartItem
エンティティを作成します.package me.jincrates.gobook.domain.carts;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import me.jincrates.gobook.domain.items.Item;
import javax.persistence.*;
@NoArgsConstructor
@Getter
@Table(name = "cart_item")
@Entity
public class CartItem {
@Id
@GeneratedValue
@Column(name = "cart_item_id")
private Long id;
@ManyToOne
@JoinColumn(name = "cart_id")
private Cart cart;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
private int count;
@Builder
public CartItem(Cart cart, Item item, int count) {
this.cart = cart;
this.item = item;
this.count = count;
}
}
エンティティにマッピングされたテーブル@JoinColumn
に외래키(FK)
が名前に設定された値が追加されていることがわかります.どのテーブルにカラムが追加されたかが混同される場合がありますが、@JoinColumnで宣言されたエンティティにカラムを追加できます.マルチペア/ペアマルチ双方向マッピング
デュアルポートマッピングには、2つの一方向マッピングが考えられる.受注と受注商品のマッピングを双方向に設定します.まず、設計は
주문
エンティティおよび주문 상태
enumを表す.package me.jincrates.gobook.domain.orders;
public enum OrderStatus {
ORDER, CANCEL
}
package me.jincrates.gobook.domain.orders;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import me.jincrates.gobook.domain.members.Member;
import javax.persistence.*;
import java.time.LocalDateTime;
@Getter @ToString
@NoArgsConstructor
@Table(name = "orders")
@Entity
public class Order {
@Id
@GeneratedValue
@Column(name = "order_id")
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
private LocalDateTime orderDate; //주문일
@Enumerated(EnumType.STRING)
private OrderStatus orderStatus; //주문상태
}
@Table(name = "orders")
:ソート時にキーワード「order
」が使用されるため、Orderエンティティにマッピングされたテーブルとして「orders
」を指定します.다대일 단방향 매핑
に従います.package me.jincrates.gobook.domain.orders;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import me.jincrates.gobook.domain.items.Item;
import javax.persistence.*;
import java.time.LocalDateTime;
@Getter @ToString
@NoArgsConstructor
@Table(name = "order_item")
@Entity
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "order_item_id")
private Long id;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
@ManyToOne
@JoinColumn(name = "order_id")
private Order order;
private int orderPrice; //주문가격
private int count; //수량
@Builder
public OrderItem(Item item, Order order, int orderPrice, int count) {
this.item = item;
this.order = order;
this.orderPrice = orderPrice;
this.count = count;
}
}
1つのテーブルでは、外部キーを使用して双方向にクエリーできますが、エンティティはテーブルとは異なります.エンティティが双方向の関連付けに設定されている場合、オブジェクトの参照は2つであり、外部キーは1つであるため、誰が外部キーを管理するかを決定する必要があります.package me.jincrates.gobook.domain.orders;
///...impoert 생략
import java.util.ArrayList;
import java.util.List;
@Getter @ToString
@NoArgsConstructor
@Table(name = "orders")
@Entity
public class Order {
//...코드 생략
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems = new ArrayList<>();
//...코드 생략
}
@OneToMany(mappedBy = "order")
:受注エンティティとの一対のマルチマッピング.外部キー(order id)はorder_item
テーブルにあるため、関連関係の所有者はOrderItem
エンティティである.Order
エンティティは所有者ではありませんので、関連付けられた関係の所有者を「mappedBy
」属性で設定してください.マルチペアマルチマッピング-Xの使用
多くのJPA書では多対多マッピングについても言及されているが,それらは実際の操作では使用されないマッピング関係である.複数対のマルチマッピングを使用しないのは、カラムを接続テーブルに追加できないためです.「接続」(Connection)テーブルには、通常、追加のカラムと結合カラムが必要です.また、エンティティをクエリーする場合、どのクエリー文が実行されるかを予測するのは難しいです.したがって、マルチマッピングではなく、1対のマルチマッピングに設定できます.
Reference
この問題について(関連関係マッピング1-関連関係マッピングタイプ), 我々は、より多くの情報をここで見つけました https://velog.io/@jincrates/연관-관계-매핑1-연관-관계-매핑-종류テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol