@ManyToOne -> 앞쪽에 있는 many가 쓰는 테이블 본인!
player - team
@Entity
public class Player {
@Id int playerId;
String playerName;
@ManyToOne -> 외래키가 되는 것.
@Column(name = "team_id")
Team team;
}
-> team_id 이름의 속성으로 외래키가 만들어짐.
이전 포스트에도 간략하게 설명했지만 junit은 단위테스트를 말한다.
@SpringBootTest
class DatabaseTests {
@Autowired PlayerRepository playerRepository;
@Test
void contextLoad() {
List<Player> list = playerRepository.findAll();
//반복문
list.stream().forEach((player) -> {
System.out.println(player);
});
}
반복문을 람다식으로 표현하기 위해 stream()를 사용해봤는데, stream으로 map을 사용하기에 편리하다.
이런식으로, @Test 어노테이션을 붙이면 메소드 별로 테스트가 가능하다.

디버그 콘솔에 보면 실행이 잘 된 것을 볼 수 있다!
보기 좋게 string으로 바꿔주기 위해 tostring object 상속을 받아야 하지만, @Data만 붙이면 알아서 스프링부트가 처리해준다.


@OneToMany(mapperBy = "team")
양방향 관계 맺기위한 코드이다.
상대(player)에서 사용하는 변수 명을 넣어 주어야 한다.
many인 player를 표현하기 위해서 밑에는 list로 player를 받았다.
이제, 위의 테스트와 똑같이 만들어 테스트해보면,
org.hibernate.LazyInitializationException:
일명 lazy 오류가 난다.
그 이유는, 팀은 db에 플레이어 정보가 없기 때문에 조회 전에 플레이어 정보를 가져와야 한다. (db에서 확인 가능, N : 1 관계에서 1 쪽이 문제!)
해결 방법 1. @OneToMany(mappedBy = "team", fetch = FetchType.EAGER)
-> 정보 먼저 조회
해결방법 2. @Transactional (추천)
-> findAll 후, 계속 연결을 유지
해결방법 3. fetch join(jpql)
따라서.. OneToMany는 최대한 사용하지 않는게 마음이 편하다.
-> 양방향 참조 때문에 발생하는 오류
-> 출력할 때 팀에서 플레이어가 들어있고, 팀 전체를 출력하려고 할때 서로가 서로를 부르는 오버플로우 상황 발생
목표 : 내가 출력하고 싶은 데이터만 json을 출력하고 싶음.
Entity를 그냥 출력하려고 할때는 데이터의 모든 것이 출력되어 매우 비효율적이다. 따라서, DTO를 사용해서 데이터를 가공하는 것이다. DTO는 entity의 어노테이션을 다 뺀 내용과 같다. (단, @Data는 있어야함)
@GetMapping("/team")
public List<TeamDTO> team() {
List<Team> list = teamRepository.findAll();
List<TeamDTO> dtoList = list.stream().map((team) -> {
TeamDTO dto = new TeamDTO();
dto.setTeamId(team.getTeamId());
dto.setTeamName(team.getTeamName());
return dto;
}).toList();
return dtoList;
}

이런 식으로, 내가 원하는 내용한 뽑아서 출력할 수 있다. 실무에서 Entity -> DTO 변환은 거의 필수라고 한다.
이렇게 변환 함으로써, 오버플로우 문제도 같이 해결된다.
목표 : 플레이어 이름과, 팀 이름( N : 1 관계인 TEAM의 이름) 가져와서 JSON형식으로 출력
@GetMapping("/player")
public List<PlayerDTO> plyer() {
List<Player> list = playerRepository.findAll();
List<PlayerDTO> dtoList = list.stream().map((player) -> {
PlayerDTO dto = new PlayerDTO();
dto.setPlayerName(player.getPlyerName());
Team t = player.getTeam();
TeamDTO dto2 = new TeamDTO();
dto2.setTeamName(t.getTeamName());
dto.setTeam(dto2);
return dto;
}).toList();
return dtoList;
}

이런식으로 원하는 정보만 선별해서 잘 출력된 것을 알 수 있다.
요약 : DTO 클래스를 Entity에 포함시켜 따로 빼기
@NoArgsConstructor @AllArgsConstructor 어노테이션 추가public PlayerDTO toDto() {
TeamDTO teamDto = (team != null) ?
new TeamDTO(team.getTeamId(), team.getTeamName(), null) : null;
return new PlayerDTO( playerId, playerName, teamDto);
}
public PlayerDTO toDtoWithoutTeam() {
return new PlayerDTO(playerId, playerName, null);
}
코드 형태가 닟선건 그냥 암기해서 익숙해지기로.. ^^!
@JsonInclude(JsonInclude.Include.NON_NULL) : null이 아닌 것만 출력하는 코드Query Method란? 메소드 이름을 통해 SQL을 생성하는 방식이다.
Repository에 작성한다.
List<Titanic> findByNameContaining(String name);
어떤 이름을 포함하는 찾기 sql문
이런식으로, 쭉 나열해서 메소드를 작성하면 된다.
험난했던 일주일이 끝났다. 완벽하게 모든 개념들을 습득했다고 자신은 못하지만 열심히 흐름을 따라가려고 노력했던 것 같다. 주말에는 푹 쉬면서 배운거를 천천히 복습해야지...