반응형
1:N 관계 예제
- 상황 : Team에는 여러 Player가 속할 수 있지만, 한 Player는 여러 팀에 속할 수 없는 1:N 관계
- Team 객체에는 id와 name 정보가 들어가고, Player 객체에는 id, name, age 정보가 들어감
- 각각의 id가 primary key(기본키)로 지정
- 연관관계 매핑
- 하나의 엔티티에 다른 엔티티의 primary key를 foreign key(외래키)로 가져와야 함
- 이런 상황에서는 보통 1:N 관계에서 N쪽으로 foreign key를 가져오고, 연관관계의 주인으로 지정함
- 이 예제에서는 team이 1, player가 N에 해당하므로 player가 연관관계 주인이 되고, team_id를 가져옴
- 이 상황을 JPA를 사용해 객체 생성 및 DB 연결 해보는 예제 (양방향 매핑)
구현 코드
Team Entity
List<Player> players에는 team에 속한 player들을 arraylist형태로 넣어줌
- Team이 1이므로 @OneToMany 어노테이션 사용
- mappedBy는 연관관계 주인이 아닌쪽에 써줌 => Player.team에 Team 객체가 들어가기 때문에 mappedBy = "team"
@Entity
@Data
public class Team {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "team_id")
private Long id;
private String name;
// 연관관계 매핑
@OneToMany(mappedBy = "team")
private List<Player> players = new ArrayList<>();
}
Player Entity
- Player가 N에 해당하므로 @ManyToOne 사용
- FetchType.LAZY 적용
FetchType
- FetchType에는 지연로딩(LAZY)와 즉시로딩(EAGER)가 있음
- EAGER은 Player을 조회할 때 Team에 대한 정보를 즉시 가져옴
- LAZY는 Player의 Team이 필요할 때 정보를 가져옴
- Player의 수가 많아질수록 LAZY를 써야 효율적임
- @OneToMany, @ManyToMany는 default가 LAZY방식이지만, @OneToOne, @ManyToOne은 default가 EAGER이기 때문에 따로 지정해 줘야 함
@Entity
@Data
public class Player {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "player_id")
private Long id;
private String name;
private Integer age;
// 연관관계 매핑
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
}
Team 추가
- Team을 추가할 때는 Player에 관한 정보는 필요 없음
@PostMapping("/team")
public String addTeam(@RequestBody String teamName) {
Team newTeam = new Team();
newTeam.setName(teamName);
teamRepository.save(newTeam);
return "Team 추가 성공";
}
Team 추가 결과
Player 추가
- Player을 추가할 때는 teamId 필요
- 입력받은 teamId를 통해 해당 team을 찾아오고, Player에 찾아온 Team을 넣어주는 방식
- name, age, teamId를 입력받기 위해 PlayerAddRequest라는 DTO 사용
@PostMapping("/player")
public String addPlayer(@RequestBody PlayerAddRequest request) {
Player player = new Player();
player.setName(request.getName());
player.setAge(request.getAge());
player.setTeam(teamRepository.findById(request.getTeamId()).get());
playerRepository.save(player);
return "Player 추가 성공";
}
// PlayerAddRequset.class
@Getter
@AllArgsConstructor
public class PlayerAddRequest {
private String name;
private Integer age;
private Long teamId;
}
Player 추가 결과
- Player가 연관관계 주인이기 때문에 team_id라는 column에 Team의 id가 들어간 것을 확인할 수 있음
Player 조회
- Player을 조회할 때에도 DTO를 사용해야 함
- Player의 Team을 가져올 때 발생하는 순환 참조 문제 해결을 위해 DTO 사용
- 입력받은 playerId로 Player을 찾아오고 PlayerDto로 변환해 출력
- 변환하는 과정에서 Team을 불러올 때 player.getTeam()을 통해 Player의 Team을 쉽게 가져올 수 있음
@GetMapping("/player/{playerId}")
public String showPlayer(@PathVariable Long playerId) {
Player player = playerRepository.findById(playerId).get();
PlayerDto playerDto = PlayerDto.of(player);
return playerDto.toString();
}
// PlayerDto.class
@AllArgsConstructor
@Builder
@ToString
public class PlayerDto {
private Long id;
private String name;
private Integer age;
private String teamName;
// Player -> PlayerDto로 변환하는 함수
public static PlayerDto of(Player player) {
return PlayerDto.builder()
.id(player.getId())
.name(player.getName())
.age(player.getAge())
.teamName(player.getTeam().getName())
.build();
}
}
Player 조회 결과
Team 조회
- Team 조회시에도 Player와 마찬가지로 DTO 사용
- Team의 Player에 접근 시에도 team.getPlayers()로 접근할 수 있음
- players는 List 타입이기 때문에 stream을 사용하여 각각의 player에 접근하고 player의 name만 추출해 playersName에 넣어줌
@GetMapping("/team/{teamId}")
public String showTeam(@PathVariable Long teamId) {
Team team = teamRepository.findById(teamId).get();
TeamDto teamDto = TeamDto.of(team);
return teamDto.toString();
}
// TeamDto.class
@AllArgsConstructor
@Builder
@ToString
public class TeamDto {
private Long id;
private String name;
private List<String> playersName;
public static TeamDto of(Team team) {
return TeamDto.builder()
.id(team.getId())
.name(team.getName())
.playersName(team.getPlayers().stream().map(list -> {
return list.getName();
}).collect(Collectors.toList()))
.build();
}
}
Team 조회 결과
반응형
'Spring Boot > 문법 정리' 카테고리의 다른 글
[Spring Boot] 연관관계 매핑 - N:M 관계 예제 (0) | 2023.01.01 |
---|---|
[Spring Boot] 연관관계 매핑 - 1:1 관계 예제 (+ @PostConstruct를 사용한 초기 데이터 생성) (0) | 2023.01.01 |
[Spring Boot] 연관관계 매핑 - 1:1, 1:N, N:M (0) | 2022.12.31 |
[Spring Boot] Swagger 3.0 적용 (0) | 2022.07.09 |
[Spring Boot] JpaRepository를 사용한 CRUD 예제 (0) | 2022.07.08 |