프로젝트를 진행하면서 1:N 매핑 관련 API를 작성하는데 어려움이 있었어서 글을 작성하게 되었습니다. 그룹을 생성하고, 그룹을 생성한 멤버가 해당 그룹의 팀장 역할을 갖도록 하는 기능을 구현했습니다.
공부 기록용이기 때문에 틀리거나 미흡한 내용이 있을 수 있습니다.
한 멤버는 여러 그룹을 생성할 수 있고, 그룹에는 여러 멤버가 가입할 수 있습니다.
ManyToMany를 사용하지 않은 이유?
@ManyToMany 어노테이션을 사용해 다대다 연관관계를 맺을 수도 있습니다. 하지만 그런 조인 방식으로 만든 매핑테이블에는 추가 컬럼을 만들 수 없다는 문제점이 있어 중간테이블을 만드는 방식을 사용했습니다.
GroupMember.java
public class GroupMember {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id")
private Group group;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
@Enumerated(EnumType.STRING)
private GroupRole groupRole;
public GroupMember(Group group, Member member, String groupRole) {
this(group, member, GroupRole.find(groupRole));
}
private GroupMember(Group group, Member member, GroupRole groupRole) {
this.group = group;
this.member = member;
this.groupRole = groupRole;
}
}
Group.java
public class Group extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Enumerated(EnumType.STRING)
private Interest interest;
@Lob
private String introduce;
@OneToMany(mappedBy = "group", cascade = CascadeType.ALL)
private List<GroupMember> groupMembers = new ArrayList<>();
public Group(String name, String interest, String introduce) {
this(name, Interest.find(interest), introduce);
}
private Group(String name, Interest interest, String introduce) {
this.name = name;
this.interest = interest;
this.introduce = introduce;
}
public void putGroupMember(GroupMember groupMember) {
this.groupMembers.add(groupMember);
}
}
mappedBy
속성을 사용해 연관관계의 주인(GroupMember)와 연관관계가 있다고 알려줌연관관계의 주인은 ?
⇒ 외래키가 있는 곳!
- 양방향 연관관계 매핑 시 두 연관관계 중 하나를
연관관계의 주인
으로 정해야 합니다.- 연관관계의 주인만이 데이터베이스 연관관계와 매핑됩니다.
- 연관관계의 주인만이 외래키를 관리(등록, 수정, 삭제)할 수 있습니다.
- 주인이 아닌 곳은 읽기만 가능합니다.
GroupService.java
@Service
@AllArgsConstructor
public class GroupService {
private final GroupRepository groupRepository;
private final MemberRepository memberRepository;
@Transactional
public void createGroup(CreateGroupRequest request) {
Member member = memberRepository.findByEmail(request.getEmail())
.orElseThrow(() -> new IllegalArgumentException("Member not found"));
if (groupRepository.existsByName(request.getName())) {
throw new IllegalArgumentException("Duplicate group name");
}
Group group = new Group(request.getName(), request.getInterest(), request.getIntroduce());
GroupMember groupMember = new GroupMember(group, member, "LEADER");
group.putGroupMember(groupMember);
groupRepository.save(group);
}
}
createGroup
GroupController.java
@RestController
@AllArgsConstructor
@RequestMapping("/api/group")
public class GroupController {
private GroupService groupService;
@Operation(summary = "그룹 생성")
@PostMapping
public ResponseEntity<Void> createGroup(@RequestBody CreateGroupRequest request) {
groupService.createGroup(request);
return ResponseEntity.noContent().build();
}
}
postman으로 생성 api 실행
Group 테이블
GroupMember 테이블
데이터가 모두 잘 들어갑니다