'manytomany'에 해당되는 글 2건
- 2015.12.23 :: jpa ManyToMany에 Column 추가하기
- 2015.12.07 :: hibernate(9)
hibernate나 jpa나 구동 방식은 매우 흡사하나. jpa는 repository를 제공한다. 기본적으로 두개다 m:n의 경우 manytomany라는 어노테이션을 사용 하지만 가끔 m:n의 테이블에 추가 컬럼을 쓸경우가 생긴다.
이때는 manytomany라는 어노테이션을 사용하지 않고 oneToMany를 사용하여 m:n 테이블에 컬럼을 추가한다. 그럼 예제를 보자.
먼저 예제는 project라는 테이블과 person 테이블이 있고 이들을 project_groups라는 테이블로 OneToMany로 맵핑하는 구조이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | package com.zest.jpa.manytomanyextracolumn; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; @Entity(name="person") public class Person { private int idx; private String name; private String email; private String password; private List<Group> groups; public Person() { // TODO Auto-generated constructor stub } public Person(String name, String email, String password) { // TODO Auto-generated constructor stub this.name = name; this.email = email; this.password = password; } public Person(String name, String email, String password, List<Group> groups) { // TODO Auto-generated constructor stub this.name = name; this.email = email; this.password = password; this.groups = groups; } @Id @GeneratedValue(strategy = GenerationType.AUTO) public int getIdx() { return idx; } public void setIdx(int idx) { this.idx = idx; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @OneToMany(mappedBy = "person", cascade = CascadeType.ALL) public List<Group> getGroups() { return groups; } public void setGroups(List<Group> groups) { this.groups = groups; } @Override public String toString() { // TODO Auto-generated method stub return "name=" + name + ", password=" + password + ", email=" + email; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | package com.zest.jpa.manytomanyextracolumn; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; @Entity(name="project") public class Project { private int idx; private String name; private String description; private List<Group> groups; public Project() { // TODO Auto-generated constructor stub } public Project(String name, String description){ this.name = name; this.description = description; this.groups = new ArrayList<Group>(); } @Id @GeneratedValue(strategy = GenerationType.AUTO) public int getIdx() { return idx; } public void setIdx(int idx) { this.idx = idx; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @OneToMany(mappedBy = "project", cascade = CascadeType.ALL, fetch=FetchType.LAZY) public List<Group> getGroups() { return groups; } public void setGroups(List<Group> groups) { this.groups = groups; } @Override public String toString() { // TODO Auto-generated method stub return "name=" + name + ", desc=" + description; } } | cs |
각 클래스는 @OnetoMany라는 어노티에션이 groups() 메소드에 묶여 있다. 그럼 이들을 묶어주는 groups 클래스를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | package com.zest.jpa.manytomanyextracolumn; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; @Entity(name="project_groups") public class Group implements Serializable { private String role; private Person person; private Project project; public Group() { // TODO Auto-generated constructor stub } public Group(Person person, Project project, String role) { this.person = person; this.project = project; this.role = role; } @Column(name = "role") public String getRole() { return role; } public void setRole(String role) { this.role = role; } @Id @ManyToOne @JoinColumn(name="person_id") public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } @Id @ManyToOne @JoinColumn(name="project_id") public Project getProject() { return project; } public void setProject(Project project) { this.project = project; } } | cs |
각 테이블과 맵핑되는 객체에 @ManyToOne이 존재하며 @JoinColumn으로 fk를 걸어주었다. 그리고 extra column으로 role이 존재 한다.
마지막 테스크 코드를 보자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Test public void projectMakeEx(){ Person person = new Person("gno2222222", "gnogun@naver.com", "gno"); Project project = new Project("project122222", "description"); Group group = new Group(person, project, "owner"); project.getGroups().add(group); personRepository.save(person); projectRepository.save(project); } | cs |
각 person과 project의 repository를 사용하여 save를 하고 group은 project에 add 리스트를 해주었다. 구조가 project가 추가 되면 group도 추가 되는 구조이기때문에 위 처럼 선언한것이다. 물론 반대인 경우 person이 추가될때 그럼을 add 해도 추가 된다.
소스는 https://github.com/zest133/hibernateTest.git 에 있으며 기존 hibernate 소스는 이 예제때문에 hibernate 버전이 변경 됨에 따라 소스 부분이 변경된 곳이 있을것이다.
다대다에 대해서 알아보자.
바로 소스 공개...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | package com.zest.hibernate.chapter8.manytomanymapping; import java.util.ArrayList; import java.util.List; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; @Entity public class Delegate { private int delegateId; private String delegateName; private List<Event> events = new ArrayList<Event>(); @Id @GeneratedValue public int getDelegateId() { return delegateId; } public void setDelegateId(int delegateId) { this.delegateId = delegateId; } public String getDelegateName() { return delegateName; } public void setDelegateName(String delegateName) { this.delegateName = delegateName; } // 결과를 담을 테이블명을 정의 . @ManyToMany @JoinTable(name = "JOIN_DELEGATE_EVENT", joinColumns = { @JoinColumn(name = "delegateId") }, inverseJoinColumns = { @JoinColumn(name = "eventId") } ) public List<Event> getEvents() { return events; } public void setEvents(List<Event> events) { this.events = events; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package com.zest.hibernate.chapter8.manytomanymapping; import java.util.ArrayList; import java.util.List; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; @Entity public class Event { private int eventId; private String eventName; private List<Delegate> delegates = new ArrayList<Delegate>(); @Id @GeneratedValue public int getEventId() { return eventId; } public void setEventId(int eventId) { this.eventId = eventId; } public String getEventName() { return eventName; } public void setEventName(String eventName) { this.eventName = eventName; } @ManyToMany @JoinTable(name = "JOIN_DELEGATE_EVENT", joinColumns = { @JoinColumn(name = "eventId") }, inverseJoinColumns = { @JoinColumn(name = "delegateId") }) public List<Delegate> getDelegates() { return delegates; } public void setDelegates(List<Delegate> delegates) { this.delegates = delegates; } } | cs |
두개의 객체를 선언하였다. 여기도 마찬가지로 새로운 어노테이션이 등장한다.
@ManyToMany 이다. 그리고 JoinColumn이 아닌 JoinTable이다.
@ManyToMany는 두개의 객체 두군데 다 선언을 한다. 그리고 필연적으로 @JoinTable을 사용해야한다. 각 속성을 알아보자. name은 m:n에 대한 데이터를 저장하는 테이블 이며, jonColumns와 inverseJoinColumkns가 존재한다. joinColumns는 join이 되는 컬럼 여기선 상호간의 컬럼 아이디를 써준다.
결과 쿼리를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Hibernate: insert into TESTSCHEMA.Delegate (delegateName, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.Delegate (delegateName, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.Delegate (delegateName, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.Delegate (delegateName, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.Event (eventName, eventId) values (?, ?) Hibernate: insert into TESTSCHEMA.Event (eventName, eventId) values (?, ?) Hibernate: insert into TESTSCHEMA.Event (eventName, eventId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) | cs |
JOIN_DELEGATE_EVENT 테이블 생성되며 각 각의 정보가 m:n으로 맵핑이 된다.
하이버네이트 모든 코드는 https://github.com/zest133/hibernateTest.git 여기에 저장되어 있다.