[JPA] ๋ค๋๋ค ๋จ๋ฐฉํฅ, ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ ๋งคํ
by rlaehddnd0422๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ ๊ทํ๋ ํ ์ด๋ธ 2๊ฐ๋ก ๋ค๋๋ค ๊ด๊ณ๋ฅผ ํํํ ์ ์์ต๋๋ค.
๊ทธ๋์ ํ ์ด๋ธ์์๋ ๋ณดํต ๋ค๋๋ค ๊ด๊ณ๋ฅผ ์ผ๋๋ค + ๋ค๋์ผ ๊ด๊ณ๋ก ํ์ด๋ด๋ ์ฐ๊ฒฐ ํ ์ด๋ธ์ ์ฌ์ฉํฉ๋๋ค.
ํ์ง๋ง ๊ฐ์ฒด๋ ํ ์ด๋ธ๊ณผ ๋ฌ๋ฆฌ @ManyToMany๋ฅผ ์ฌ์ฉํด์ ๊ฐ์ฒด 2๊ฐ๋ก ๋ค๋๋ค ๊ด๊ณ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
๋ค๋๋ค ๋จ๋ฐฉํฅ
๋ค๋๋ค Member โก๏ธ Item์ @ManyToMany๋ก ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํด๋ณด๊ฒ ์ต๋๋ค.
Member
@Entity
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@ManyToMany
@JoinTable(name = "MEMBER_ITEM",
joinColumns = @JoinColumn(name = "MEMBER_ID"),
inverseJoinColumns = @JoinColumn(name = "ITEM_ID"))
private List<Item> items = new ArrayList<Item>();
...
}
- Member ์ํฐํฐ์ Item ์ํฐํฐ๋ฅผ @ManyToMany๋ก ๋งคํํ์์ต๋๋ค.
- @JoinTable๋ฅผ ์ฌ์ฉํ๋ฉด ์ค๊ฐ ์ฐ๊ฒฐ ํ
์ด๋ธ ์ํฐํฐ๋ฅผ ์ง์ ์์ฑํ์ง ์๊ณ ๊ฐ์ ์ ์ผ๋ก ๋งคํํ ์ ์์ต๋๋ค.
- @JoinTable.name : ์ฐ๊ฒฐ ํ ์ด๋ธ ์ด๋ฆ ์ง์
- @JoinTable.joinColumns : ํ์ฌ ๋ฐฉํฅ์ธ Member์ ๋งคํํ ์กฐ์ธ ์ปฌ๋ผ ์ ๋ณด ์ง์
- @JoinTable.inverseJoinColumns : ๋ฐ๋ ๋ฐฉํฅ์ธ Item๊ณผ ๋งคํํ ์กฐ์ธ ์ปฌ๋ผ ์ ๋ณด ์ง์
- MEMBER_ITEM ํ ์ด๋ธ์ ๋ค๋๋ค ๊ด๊ณ๋ฅผ ์ผ๋๋ค-๋ค๋์ผ ๊ด๊ณ๋ก ํ์ด๋ด๊ธฐ ์ํด ํ์ํ ์ฐ๊ฒฐ ํ ์ด๋ธ์ผ ๋ฟ์ด๊ธฐ ๋๋ฌธ์ ์ฐ๊ฒฐ ํ ์ด๋ธ์ ๋ํด์๋ ์ ๊ฒฝ์ฐ์ง ์์๋ ๋ฉ๋๋ค.
@Entity
public class Item{
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
...
}
์ ์ฅ
try
{
Item item = new Item();
item.setName("์ํA");
em.persist(item);
Item item2 = new Item();
item2.setName("์ํB");
em.persist(item2);
Member member = new Member();
member.setName("ํ์A");
member.getItems().add(item); // ์ฐ๊ด๊ด๊ณ Member -> Item ์ค์
member.getItems().add(item2); // ์ฐ๊ด๊ด๊ณ Member -> Item ์ค์
em.persist(member);
for (Item memberItem : member.getItems()) {
System.out.println("memberItem = " + memberItem.getName());
}
tx.commit();
} catch (Exception e) {
tx.rollback();
}finally {
em.close();
}
emf.close();
}
ํ์A์ ๋ํ ์ํA์ ์ฐ๊ด๊ด๊ณ๋ฅผ ์ค์ ํ๊ธฐ ๋๋ฌธ์ ํ์A๋ฅผ ์ ์ฅํ ๋ ์ฐ๊ฒฐ ํ ์ด๋ธ์๋ ๊ฐ์ด ์ ์ฅ๋ฉ๋๋ค.
insert into item ... // itemA
insert into item ... // itemB
insert into member ... // memberA
insert into member_item ...
๋ค๋๋ค ์๋ฐฉํฅ
๋ค๋๋ค ์ญ๋ฐฉํฅ๋ ๋ค๋๋ค์ด๋ฏ๋ก ๋ง์ฐฌ๊ฐ์ง๋ก @ManyToMany๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์์ชฝ ์ค ์ํ๋ ๊ณณ์ mappedBy๋ฅผ ์ง์ ํด์ ๋ฐ๋ ์ชฝ์ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ์ง์ ํฉ๋๋ค.
Member
@Entity
public class Member{
@Id @GeneratedValue
@Column(name="MEMBER_ID")
private Long id;
private String name;
@ManyToMany
@JoinTable(name = "MEMBER_ITEM",
joinColumns = @JoinColumn(name="MEMBER_ID"),
inverseJoinColumns = @JoinColumn(name="ITEM_ID"))
private List<Item> items = new ArrayList<Item>();
...
}
Item
@Entity
public class Item{
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
@ManyToMany(mappedBy = "items")
private List<Member> members;
}
// In Member Entity
public void addItem(Item item){
items.add(item);
item.getMembers().add(this);
}
์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ ๋ฐ๋์ ์ฐ๊ด๊ด๊ณ ํธ์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํด์ ๊ด๋ฆฌํ๋๋ก ํฉ์๋ค.
์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋ง๋ค์๊ธฐ ๋๋ฌธ์ ์ด์ Item์์๋ getMembers()๋ฅผ ์ฌ์ฉํด์ ์ญ๋ฐฉํฅ ๊ฐ์ฒด ๊ทธ๋ํ ํ์์ด ๊ฐ๋ฅํด์ก์ต๋๋ค.
@ManyToMany๋ฅผ ์ฌ์ฉํ๋ฉด ์ฐ๊ฒฐ ํ ์ด๋ธ์ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ฃผ๊ธฐ ๋๋ฌธ์ ๋๋ฉ์ธ ๋ชจ๋ธ์ด ๋จ์ํด์ง๊ณ ํธ๋ฆฌํด์ง์ง๋ง, ์ค๋ฌด์์ ์ฌ์ฉํ๊ธฐ์๋ ํ๊ณ๊ฐ ์์ต๋๋ค.
์๋ฅผ๋ค์ด Member ์ํฐํฐ์ Item ์ํฐํฐ๊ฐ ์์ ๋, Member๊ฐ Item์ ์ฃผ๋ฌธํ๋ฉด Item Id๋ง ๋ด๊ณ ๋๋ ๊ฒ ์๋๋ผ, ์ฐ๊ฒฐ ํ ์ด๋ธ์ ์ฃผ๋ฌธ ์๋์ด๋, ์ฃผ๋ฌธ ๋ ์ง, ์ฃผ๋ฌธ ๊ธ์ก๊ณผ ๊ฐ์ ์ปฌ๋ผ์ด ํ์ํฉ๋๋ค.
์ด๋ฐ ๊ฒฝ์ฐ ์ง์ ์ฐ๊ฒฐ ํ ์ด๋ธ์ ์์ฑํ๊ณ ์ฐ๊ฒฐ ํ ์ด๋ธ์ ์ถ๊ฐํ ์ปฌ๋ผ๋ค์ ๋งคํํ๊ณ , ์ผ๋๋ค - ์ฐ๊ฒฐํ ์ด๋ธ - ๋ค๋์ผ๋ก ํ์ด์ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํด์ฃผ๋๊ฒ์ด ์ข์ต๋๋ค.
์ฝ๋๋ก ํ๋ฒ ๋ฐ๋ผ๊ฐ๋ณด๊ฒ ์ต๋๋ค.
๋ค๋๋ค ๋งคํ : ์ฐ๊ฒฐ ์ํฐํฐ ์ฌ์ฉ
์ฐ๊ฒฐ ์ํฐํฐ๋ฅผ ์ง์ ๋ง๋ค์ด ๋ค๋๋ค ๋งคํ์ ํด๋ด ์๋ค.
Member
@Entity
public class Member {
@Id @GeneratedValue
@Column(name="MEMBER_ID")
private Long id;
private String name;
@OneToMany(mappedBy = "member")
private List<MemberItem> Memberitem = new ArrayList<MemberItem>();
...
}
- MemberItem ์ชฝ์ด ์ธ๋ํค๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฏ๋ก ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ด ๋ฉ๋๋ค. ๋ฐ๋ผ์ mappedBy ์์ฑ์ ์ถ๊ฐํด์ค์๋ค.
Item
@Entity
public class Item{
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
// ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ ๋งคํ : Item->MemberItem ์กฐํ๋ฅผ ์ํ๋ ๊ฒฝ์ฐ
// @OneToMany(mappedBy = "item")
// private List<MemberItem> memberItem = new ArrayList<MemberItem>();
...
}
- Item์ผ๋ก MemberItem ์กฐํ๋ฅผ ์ํ๋ ๊ฒฝ์ฐ ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ ๋งคํ : MemberItem ์ชฝ์ด ์ธ๋ํค๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฏ๋ก ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ด ๋ฉ๋๋ค. ๋ฐ๋ผ์ mappedBy ์์ฑ์ ์ถ๊ฐํด์ค์๋ค.
MemberItem (์ฐ๊ฒฐ ์ํฐํฐ)
@Entity
@IdClass(MemberProductId.class)
public class MemberItem{
@Id
@ManyToOne
@JoinColumns(name= "MEMBER_ID")
private Member member;
@Id
@ManyToOne
@JoinColumns(name= "ITEM_ID")
private Item item;
private Integer orderAmount;
@Temporal(TemporalType.DATE)
private Date orderDate;
...
}
๊ฐ์ฅ ์ค์ํ ์ฐ๊ฒฐ ์ํฐํฐ MemberItem์ ์ดํด๋ด ์๋ค.
MemberItem ์ํฐํฐ๋ฅผ ๋ณด๋ฉด ๊ธฐ๋ณธํค๋ฅผ ๋งคํํ๋ @Id์ ์ธ๋ํค๋ฅผ ๋งคํํ๋ @JoinColumns๋ฅผ ๋์์ ์ฌ์ฉํด์ member_id์ item_id๋ฅผ ๊ธฐ๋ณธํค + ์ธ๋ํค๋ฅผ ํ๋ฒ์ ๋งคํํ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ @IdClass๋ฅผ ์ฌ์ฉํด์ ๋ณตํฉ ๊ธฐ๋ณธ ํค๋ฅผ ๋งคํํ์ต๋๋ค.
- MemberItem ์ํฐํฐ์์ ๊ธฐ๋ณธํค๋ member_id์ item_id๋ก ์ด๋ฃจ์ด์ง ๋ณตํฉํค์ ๋๋ค.
- JPA์์ ๋ณตํฉํค๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ณ๋์ ์๋ณ์ ํด๋์ค๋ฅผ ๋ง๋ค์ด์ผ ํฉ๋๋ค. (@IdClass๋ฅผ ์ฌ์ฉํด์ ์๋ณ์ ํด๋์ค๋ฅผ ์ง์ )
๋ณตํฉํค ์ฌ์ฉ ๋ณ๋ ์๋ณ์ ํด๋์ค ์์ฑ ๋ฐฉ๋ฒ
1. ๋ณ๋์ ์๋ณ์ ํด๋์ค๋ฅผ ( public์ผ๋ก ) ์์ฑ
2. Serializable์ implements
3. equals, hashCode ๋ฉ์๋ ๊ตฌํ
4. ๊ธฐ๋ณธ ์์ฑ์ ์์ฑ
public class MemberItemId implements Serializable {
private Long member; // MemberItem.member์ ์ฐ๊ฒฐ
private Long item; // MemberItem.item๊ณผ ์ฐ๊ฒฐ
public MemberItemId() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MemberItemId)) return false;
MemberItemId that = (MemberItemId) o;
if (member != null ? !member.equals(that.member) : that.member != null) return false;
return item != null ? item.equals(that.item) : that.item == null;
}
@Override
public int hashCode() {
int result = member != null ? member.hashCode() : 0;
result = 31 * result + (item != null ? item.hashCode() : 0);
return result;
}
}
- equals, hashCode ๋ฉ์๋๋ IDE์์ ์ ๊ณตํ๋ ํ๋๊ธฐ๋ฐ ์๋์์ฑ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์์ต๋๋ค.
์ ์ฅํ๋ ์ฝ๋
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
Member member1 = new Member();
member1.setId(1L);
member1.setName("ํ์1");
em.persist(member1);
Item item1 = new Item();
item1.setId(1L);
item1.setName("์ํ1");
em.persist(item1);
MemberItem memberItem = new MemberItem();
memberItem.setMember(member1); // MemberItem -> member1
memberItem.setItem(item1);
memberItem.setOrderAmount(2);
memberItem.setOrderDate(new Date());
em.persist(memberItem);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
MemberItem ์ฐ๊ฒฐ ์ํฐํฐ์์ item_id์ member_id๋ฅผ ๋ณตํฉํค๋ก ์ฌ์ฉํ์ต๋๋ค.
ํ์ง๋ง ์ด๋ ๊ฒ ๋ณต์กํ๊ฒ ๋ณตํฉํค๋ฅผ ๋งคํํด์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ์ฐ๊ฒฐ ์ํฐํฐ์๋ ๋น์ฆ๋์ค์ ์์กดํ๋ ํค๊ฐ ์๋ ๋๋ฆฌํค๋ฅผ ์ฌ์ฉํ๋ ์ ๋ต์ด ์ข์ต๋๋ค.
๋ค๋๋ค ์ฐ๊ฒฐ ์ํฐํฐ - ๋๋ฆฌํค ๋์
Member_Item ์ฐ๊ฒฐ ์ํฐํฐ์ ๊ณ ์ ์ ๋๋ฆฌํค๋ฅผ ์ฌ์ฉํ๋๋ก ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํด๋ด ์๋ค.
๊ธฐ์กด Member, Item ์ํฐํฐ๋ ๋ณ๊ฒฝ์ฌํญ X
@Entity
public class MemberItem {
@Id @GeneratedValue
@Column(name = "MEMBER_ITEM_ID")
private Long id;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@ManyToOne
@JoinColumn(name = "ITEM_ID")
private Item item;
private Integer orderAmount;
@Temporal(TemporalType.DATE)
private Date orderDate;
...
}
์ด ์ ์ ๋ฐ์์จ ์๋ณ์๋ฅผ ๊ธฐ๋ณธํค+์ธ๋ํค๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์๋ณ๊ด๊ณ๋ผ๊ณ ํ๊ณ , ๋ฐ์์จ ์๋ณ์๋ ์ธ๋ํค๋ก๋ง ์ฌ์ฉํ๊ณ ์๋ก์ด ์๋ณ์๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๋น ์๋ณ๊ด๊ณ๋ผ๊ณ ํฉ๋๋ค.
๋น์๋ณ๊ด๊ณ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์๋ณ์ ํด๋์ค๋ฅผ ๋ง๋ค์ง ์๊ณ ๋จ์ํ๊ฒ ORM ๋งคํ์ ํ ์ ์์ ๋ฟ๋๋ฌ ๋น์ฆ๋์ค ํค์ ์์กดํ์ง ์๋๋ค๋ ์ฅ์ ๋๋ฌธ์ ์ค๋ฌด์์๋ ๋ค๋๋ค ๋งคํ์์ ๋น์๋ณ๊ด๊ณ๋ฅผ ์ฌ์ฉํ๋ ์ ๋ต์ ์ ํธํฉ๋๋ค.
<์ ๋ฆฌ>
- ๋ค๋๋ค ์ฐ๊ด๊ด๊ณ๋ฅผ ์ค๊ฐ ์ฐ๊ฒฐ ์ํฐํฐ ์์ฑ์์ด 2๊ฐ์ ๊ฐ์ฒด๋ง์ผ๋ก ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํด๋ณด์์ต๋๋ค.
- ์ถ๊ฐ์ ์ธ ์ปฌ๋ผ์ด ํ์ํ ๋ ์ฌ์ฉํ ์ ์๋ค๋ ํ๊ณ๊ฐ ์์ด, ์ค๋ฌด์์๋ ์ด๋ฐ ๋ฐฉ์์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
- ๋ค๋๋ค ์ฐ๊ด๊ด๊ณ๋ฅผ ์ผ๋๋ค, ๋ค๋์ผ๋ก ํ์ด๋ณด์์ต๋๋ค.
- ์ถ๊ฐ์ ์ธ ์ปฌ๋ผ์ ์ถ๊ฐํ๊ณ , ์ฐ๊ฒฐ ์ํฐํฐ๋ฅผ ์ง์ ์์ฑํ๊ณ , ์๋ณ๊ด๊ณ๋ฅผ ์ฌ์ฉํด ์๋ณ์๋ฅผ ๊ธฐ๋ณธํค + ์ธ๋ํค๋ก ์ฌ์ฉํด ๋ค๋๋ค ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํด๋ณด์์ต๋๋ค. / ์๋ณ์ ํด๋์ค๋ฅผ ๋ณ๋๋ก ์์ฑํด์ฃผ์ด์ผ ํ๋ ๋ถํธํจ, ๋น์ฆ๋์ค ํค๋ฅผ ๋ณตํฉํค๋ก ์ฌ์ฉํ๋ ๊ฒ์ ๋ํ ์ฐ์ฐํจ์ด ๋จ์.
- ์ถ๊ฐ์ ์ธ ์ปฌ๋ผ์ ์ถ๊ฐํ๊ณ , ์ฐ๊ฒฐ ์ํฐํฐ๋ฅผ ์ง์ ์์ฑํ๊ณ , ๋น ์๋ณ๊ด๊ณ๋ฅผ ์ฌ์ฉํด ๋๋ฆฌํค๋ก ๋ค๋๋ค ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํด๋ณด์์ต๋๋ค. / ๋ณตํฉํค๋ฅผ ์ํ ์๋ณ์ ํด๋์ค๋ฅผ ๋ง๋ค ํ์๊ฐ ์๊ณ , ๋น์ฆ๋์คํค์ ์์กดํ์ง ์์ ์ค๋ฌด์์ ์์ฃผ ์ฌ์ฉํฉ๋๋ค.
<์ฐธ๊ณ ์๋ฃ>
'๐ Backend > Spring Data JPA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JPA] ๊ณ ๊ธ ๋งคํ : ๋งคํ ์ ๋ณด๋ง ์ ๊ณตํ๊ธฐ using @MappedSuperClass (0) | 2023.05.03 |
---|---|
[JPA] ๊ณ ๊ธ ๋งคํ : ์์ ๊ด๊ณ ๋งคํ (0) | 2023.05.03 |
[JPA] ๋ค๋์ผ, ์ผ๋๋ค, ์ผ๋์ผ (๋จ๋ฐฉํฅ, ์๋ฐฉํฅ) ์ฐ๊ด๊ด๊ณ ๋งคํ (0) | 2023.05.01 |
[JPA] ์ฐ๊ด๊ด๊ณ ๋งคํ - ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ (1) | 2023.04.30 |
[JPA] ์ฐ๊ด๊ด๊ณ ๋งคํ - ๋จ๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ (0) | 2023.04.29 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422