단순 데이터 조회이므로 데이터나 테이블을 변경할 일이 없습니다.
그래서 dda-auto 옵션을 none으로 바꿔놓겠습니다.
spring:
datasource:
url: jdbc:h2:tcp://localhost/~/jpashop
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
hibernate:
**ddl-auto: none**
properties:
hibernate:
# show_sql: true
format_sql: true
logging:
level:
org.hibernate.SQL: debug
org.hibernate.type: trace
이렇게 하면 테이블을 드랍하지 않기 때문에 데이터를 한 번 넣어두면 지속적으로 데이터베이스에 있는 데이터를 쓸 수 있습니다.
조회기능을 만드는데 데이터를 계속 넣는 것을 하면 귀찮으니까요..
@RestController
@RequiredArgsConstructor
public class MemberApiController {
private final MemberService memberService;
**@GetMapping("/api/v1/members")
public List<Member> membersV1() {
return memberService.findMembers();
}**
}
실행해보면 미리 넣어둔 데이터가 쭉 나오는 것을 볼 수 있습니다.
굉장히 쉽게 만들었죠? 그냥 리스트에 entity 를 반환했으니까요. 그러나 역시 문제점들이 존재합니다.
기본적으로 엔티티의 모든 값이 노출됩니다. 그래서 응답 스펙을 맞추기 위해 로직이 추가됩니다. (@JsonIgnore, 별도의 뷰 로직 등등)
지금은 회원정보만 달라고 했는데 실제 회원이 주문한게 있다면 orders 정보에 뭔가 포함되어 있겠죠?
이렇게 엔티티를 직접 노출하게 되면 엔티티에 있는 정보들이 전부 외부에 노출이 됩니다.
그럼 어떻게 해야할까요?
스프링 같은 경우 기본적으로 Jackson을 사용합니다. 그래서 @JsonIgnore 애노테이션을 넣으면 주문정보가 빠집니다. 코드로 작성해보죠.
@Entity
@Getter @Setter
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private long id;
private String name;
@Embedded
private Address address;
**@JsonIgnore**
@OneToMany (mappedBy = "member")
private List<Order> orders = new ArrayList<>();
}
이렇게 하고 실행하면 orders 정보가 빠집니다.
이렇게 해도 일단은 해결이 됩니다.. 그런데 다른 api를 만들 때 멘붕이 오게 됩니다.
회원과 관련된 조회 api는 하나가 아닐겁니다. 굉장히 다양한 api 스타일을 요구할텐 데 그 때마다 요구사항을 맞출 수가 없습니다. 모든 케이스를 대응할 수 없겠죠.
엔티티에 프레젠테이션 계층을 위한 로직이 추가됩니다.
엔티티에 화면을 뿌리기위한 로직이 추가되기 시작했습니다. 프레젠테이션 계층을 위한 로직이 추가되기 시작한 것입니다. api 스펙과 화면을 위한 기능이 엔티티에 들어와버립니다.
이렇게 되면 엔티티로 의존관계가 들어와야하는데 반대로 엔티티에서 의존관계가 나가버리게 됩니다.
양방향으로 의존관계가 걸리면서 애플리케이션을 수정하기가 굉장히 어렵게 됩니다.
실무에서는 같은 엔티티에 대해 API가 용도에 따라 다양하게 만들어지는데, 한 엔티티에 각각의 API를 위한 프레젠테이션 응답 로직을 담기는 어렵습니다.