iseunghan 2020. 11. 25. 16:49
๋ฐ˜์‘ํ˜•

 

์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ - ๊ธฐ๋ณธํŽธ์„ ๊ณต๋ถ€ํ•˜๋ฉฐ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

 

์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ - ๊ธฐ๋ณธํŽธ - ์ธํ”„๋Ÿฐ

JPA๋ฅผ ์ฒ˜์Œ ์ ‘ํ•˜๊ฑฐ๋‚˜, ์‹ค๋ฌด์—์„œ JPA๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ ๊ธฐ๋ณธ ์ด๋ก ์ด ๋ถ€์กฑํ•˜์‹  ๋ถ„๋“ค์ด JPA์˜ ๊ธฐ๋ณธ ์ด๋ก ์„ ํƒ„ํƒ„ํ•˜๊ฒŒ ํ•™์Šตํ•ด์„œ ์ดˆ๋ณด์ž๋„ ์‹ค๋ฌด์—์„œ ์ž์‹ ์žˆ๊ฒŒ JPA๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธ‰ ์›น ๊ฐœ๋ฐœ ํ”„๋กœ๊ทธ๏ฟฝ

www.inflearn.com


 

๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜ (์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋จ X, ์—”ํ‹ฐํ‹ฐ๋กœ ์Šน๊ฒฉ์‹œ์ผœ์„œ ์‚ฌ์šฉ O)

@Entity
public class Member {
	..
    
    @ElementCollection
    @CollectionoTable(name = "FAVORITE_FOOD", joinColumn = 
    @JoinColumn(name = "MEMBER_ID"))
    private Set<String> favoriteFoods = new HashSet<>();

	@ElementCollection
    @CollectionTable(name = "ADDRESS", joinColumn =
    @JoinColumn(name = "MEMBER_ID"))
	private List<Address> addressList = new ArrayList<>();
    
    ..
}

 

  • ๊ฐ’ ํƒ€์ž…์„ ํ•˜๋‚˜ ์ด์ƒ ์ €์žฅํ•  ๋•Œ Set, List๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • PK๋ฅผ ํ•˜๋‚˜๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ’ ํƒ€์ž…์ด ์•„๋‹ˆ๊ณ , ์—”ํ‹ฐํ‹ฐ ๊ฐœ๋…์ด ๋˜๋ฒ„๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’ ํƒ€์ž…์„ ๋ฌถ์–ด์„œ PK๋กœ ์„ค์ •ํ•œ๋‹ค.
  • @ElementCollection (๊ฐ’ ํƒ€์ž…์ด ์ปฌ๋ ‰์…˜์ด๋ผ๊ณ  ๋ช…์‹œ), @CollectionTable(์ปฌ๋ ‰์…˜ ํ…Œ์ด๋ธ” ์ด๋ฆ„, ์กฐ์ธ ์„ค์ •) ์‚ฌ์šฉํ•œ๋‹ค.
    • ๊ฐ’ ํƒ€์ž…์ด ํ•˜๋‚˜์ผ ๋•, Memberํด๋ž˜์Šค์— ํ•„๋“œ ์†์„ฑ์œผ๋กœ ๋„ฃ์œผ๋ฉด ๋˜์ง€๋งŒ, DB ๋‚ด๋ถ€์— ์ปฌ๋ ‰์…˜์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„์˜ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•ด์„œ ๋งคํ•‘(@CollectionTable) ์‹œ์ผœ์ค˜์•ผํ•œ๋‹ค.
  • ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์€ Member ํ…Œ์ด๋ธ”์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์— Member์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๋”ฐ๋ผ๊ฐ„๋‹ค.
    • em.persist(member)๋ฅผ ํ•ด์ฃผ๋ฉด ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜๋“ค๋„ ํ•จ๊ป˜ persist๊ฐ€ ๋œ๋‹ค.
      • ์ด๊ฒƒ์€ cascadeType.ALL + orphanRemoval = true์™€ ๊ฐ™๋‹ค. (๊ฐ’ ํƒ€์ž…์€ ์ด ๊ธฐ๋Šฅ์„ ํ•ญ์ƒ ํ•„์ˆ˜๋กœ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค.)
  • ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์—ฐ ์ „๋žต(fetch = FetchType.LAZY)์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

 

๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์˜ ์ œ์•ฝ ์‚ฌํ•ญ

  • ๊ฐ’ ํƒ€์ž…์€ ์‹๋ณ„์ž ๊ฐœ๋…์ด ์—†๋‹ค. ( ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ์ ! )
  • ์‹๋ณ„์ž๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ๋•Œ ์ถ”์ ์„ ํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค.
  • ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•˜๋ฉด , ์ฃผ์ธ ์—”ํ‹ฐํ‹ฐ์™€ ์—ฐ๊ด€๋œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๊ณ , ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์— ์žˆ๋Š” ํ˜„์žฌ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ์ €์žฅํ•œ๋‹ค.

 

๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์˜ ๋Œ€์•ˆ (์‹ค๋ฌด์—์„œ๋Š” ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค.)

  • ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์„ ์—”ํ‹ฐํ‹ฐ๋กœ ์Šน๊ฒฉ ์‹œํ‚จ๋‹ค.
    • ๊ธฐ์กด์˜ ๊ฐ’ํƒ€์ž… ์ปฌ๋ ‰์…˜์€ ์–‘๋ฐฉํ–ฅ์„ ์„ค๊ณ„ ํ•  ์ˆ˜ ์—†์—ˆ๋Š”๋ฐ, ์—”ํ‹ฐํ‹ฐ๋กœ ์Šน๊ฒฉํ•จ์œผ๋กœ์จ ์–‘๋ฐฉํ–ฅ ๋งคํ•‘์ด ๊ฐ€๋Šฅํ•ด์กŒ๋‹ค.
    • ์‹๋ณ„์ž ๊ฐœ๋…์ด ์ถ”๊ฐ€ ๋˜๋ฉด์„œ, ๊ฐ’์„ ์ถ”์  ํ•  ์ˆ˜ ์—†์—ˆ๋˜ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ์ด ๋˜์—ˆ๋‹ค.

 

๋จผ์ € ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์„ ์œ„ํ•œ ๋ณ„๋„์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

/**
 * ๊ฐ’ ํƒ€์ž… -> ์—”ํ‹ฐํ‹ฐ๋กœ ์Šน๊ฒฉ
 *
 * ID๊ฐ€ ์žˆ์–ด์„œ ์‹๋ณ„์ž๊ฐ€ ์ƒ๊ฒจ์„œ ์ด์ œ ๋งˆ์Œ๊ป ์ˆ˜์ •ํ•˜๊ณ  ์‚ญ์ œํ•  ์ˆ˜์žˆ๋‹ค.
 * ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜ ๋Œ€์‹ ์— ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์ œ์ผ ๋ง˜ ํŽธํ•˜๋‹ค.
 * ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ์œ„ํ•œ ์—”ํ‹ฐํ‹ฐ -> AddressEntity ๋ฅผ ๋งŒ๋“ค๊ณ 
 * ์—ฌ๊ธฐ์„œ private Address address; -> ๊ฐ’ ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.
 * ์˜์†์„ฑ ์ „์ด(Cascade.ALL) + orphanRemoval ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ’ํƒ€์ž… ์ปฌ๋ ‰์…˜ ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•ด๋ผ
 */
@Entity
@Table(name = "ADDRESS")
public class AddressEntity {

    @Id
    @GeneratedValue
    private Long id; // ID ์‹๋ณ„์ž ์ƒ๊น€!!!!

	@Embedded // ์‚ฌ์‹ค @Embeddable ๋‘˜ ์ค‘์— ํ•˜๋‚˜๋งŒ ์“ฐ๊ณ  ๋‚˜๋จธ์ง€๋Š” ์ƒ๋žต ํ•ด๋„ ๋œ๋‹ค. (๊ทธ์น˜๋งŒ ๋‘˜ ๋‹ค ์“ฐ๋Š”๊ฑธ ๊ถŒ์žฅํ•จ)
    private Address address; // ์—ฌ๊ธฐ์„œ ๊ฐ’ ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.

    public AddressEntity() {
    }

    // ์ด๋Ÿฐ์‹์œผ๋กœ ๊ฐ’ ํƒ€์ž…์— ์ƒ์„ฑ์ž๋ฅผ ์ด์šฉํ•ด์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด ๋„ฃ์–ด์ค€๋‹ค.
    public AddressEntity(String city, String street, String zipcode) {
        this.address = new Address(city, street, zipcode);
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

 

๊ทธ๋ฆฌ๊ณ  Member์—์„œ ๊ฐ’ ํƒ€์ž…์„ ๋งคํ•‘ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, ์—”ํ‹ฐํ‹ฐ๋กœ ๋งคํ•‘์„ ํ•ด์ค€๋‹ค.

@Entity
public class Member {

	..
    
    //@ElementCollection
    //@CollectionTable(name = "ADDRESS", joinColumns =
    //@JoinColumn(name = "MEMBER_ID"))
    //private List<Address> addressHistory = new ArrayList<>();
    
    @OneToMany(cascade = CascadeType.ALL , orphanRemoval = true)
    @JoinColumn(name = "MEMBER_ID")
    private List<AddressEntity> addressHistory = new ArrayList<>();
    
}

 

Address ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์— ๊ฐ’์„ ๋„ฃ์„ ๋•Œ๋Š” ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋œ๋‹ค.

<< Main.java >>

Member member = new Member();
member.getAddressHistory().add(new AddressEntity("city", "street", "zipcode"));

--------------------------------------------------------------------------------
<< Member.java >>

@OneToMany(cascade = ALL, orphanRemoval = true)
@JoinColumn(name = "MEMBER_ID")
private List<AddressEntity> addressHistory = new ArrayList<>();

--------------------------------------------------------------------------------
<< AddressEntity >>

private Address address;

public AddressEntity(String city, String street, String zipcode){
	this.address = new Address(city, street, zipcode);
}

List์— ์ €์žฅํ•˜๋ฉด -> member List์— ์ €์žฅ๋˜๊ณ , AddressEntity์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ String๋“ค์„ Address์ƒ์„ฑ์ž์—๊ฒŒ ๋„˜๊ฒจ์ฃผ๊ณ  address ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ ๊ฐ€์ง€๊ณ  ์žˆ๊ฒŒ ๋œ๋‹ค.

 

๊ทธ๋Ÿฌ๋ฉด ์–ธ์ œ ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

์ •๋ง~ ๋‹จ์ˆœํ•œ select Box์— [ ( ) ์น˜ํ‚จ ,  ( ) ํ”ผ์ž ] ์ด๋Ÿฐ์‹์œผ๋กœ ์ค‘๋ณตํ•ด์„œ ์„ ํƒ ํ•  ์ˆ˜ ์žˆ๋Š” ์ฒดํฌ ๋ฐ•์Šค๊ฐ€ ์žˆ๋‹ค๊ณ  ํ• ๋•Œ, ์ด๋Ÿด ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฑฐ๋‹ค 

์ด๋ ‡๊ฒŒ ์ง„์งœ ๋‹จ์ˆœํ•œ ๊ฒฝ์šฐ, ๊ฐ’์„ ์ถ”์  ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ๋Š” ์›ฌ๋งŒํ•˜๋ฉด ์—”ํ‹ฐํ‹ฐ๋‹ค.

๋ฐ˜์‘ํ˜•