-
Notifications
You must be signed in to change notification settings - Fork 152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[5기 정의진] Springboot-jpa weekly 미션 1,2,3 제출합니다. #343
base: uijin-j
Are you sure you want to change the base?
Conversation
Customer 엔티티를 이용한 CRUD 구현
order, order_item, item 엔티티 생성
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
간단하게 리뷰 했습니당! 어노테이션에 대해서 많이 알고 계신 것 같아서 많이 배운 것 같아용! 🥰
@AttributeOverride(name = "street", column = @Column(name = "street")), | ||
@AttributeOverride(name = "zip_code", column = @Column(name = "zip_code")) | ||
}) | ||
private Address address; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AttributeOverrides는 클래스 안의 필드를 컬럼으로 인식하게 해주는 것이군요 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
신기하네요.. 혹시 Address 내부에서 Column을 추가하면 이상이 있을까요? 만약 이상이 없다면 AttributeOverrides를 사용하면서 얻을 수 있는 이점이 무엇인가요??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Sehee-Lee-01 정확하게는 @Embeddable
, @Embedded
애너테이션으로 클래스를 어떤 엔티티의 속성으로 넣을 수 있다고 합니다! @AttributeOverrides
는 컬럼명을 지정해주고 싶을 때 사용하는 것 같아요:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@IjjS Address 내부에 @Column
을 추가해도 되고, @AttributeOverride
와 @Column
을 모두 쓰지 않아도 자동으로 Address의 필드명으로 DB에 저장되게 됩니다!
제 생각에 @AttributeOverrides
를 쓰는 이유는 Address를 customer 테이블에 저장할 때, 컬럼명을 지정해주기 위해서 인 것 같습니다! 예를 들어 customer가 집주소와 회사 주소를 가지고 있다면 @AttributeOverride(name = "city", column = @Column(name = "home_city"))
와 같이 사용할 수 있을 것 같아요! 그리고 Address가 또 다른 엔티티에 저장될 때, 더 의미 있는 이름으로 컬럼명을 지정하고 싶은 경우에도 좋을 것 같아요!(ex. 배송지)
그리고 다시보니 지금 저의 경우에는 @AttributeOverride
를 생략해도 될 것 같네용!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Baeldung] Jpa @Embedded and @Embeddable 이건 제가 참고 했던 링크입니다:) 참고해 보셔도 좋을 것 같아요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저는 처음에 Address라는 객체를 사용했음에도 AttributeOverrides로 명시하는 것은 캡슐화가 깨진다고 볼 수 있지 않을까? 하고 생각했는데, DB와 관련되어 있기도 하고 다른 엔티티에 저장할 때 더 의미 있는 이름으로 컬럼을 지정할 수 있다는 점은 완전 유용해보이네요!!!
|
||
@Column(name = "age") | ||
@Range(min = 0, max = 200) | ||
private Integer age; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
primitive 타입인 long, int가 아니라 Integer, Long 등 Wrapper 클래스로 하는 이유가 있나요!
제가 알기로는 null 값이 주어질 때, wrapper 클래스(null 설정)와 primitive 타입(0 설정)이 각각 값 설정이 달라서 이렇게 설정하는 걸로 알고 있어서요! 제가 잘 몰라서 확인차 여쭤봅니당!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일단 첫번째로 primitive type은 객체가 아니기 때문에 객체지향 관점에서(?) 웬만하면 Wrapper 클래스를 쓰려고 했습니당!
두번째로는 age는 필수값이 아니기 때문에 충분히 null이 들어올 수 있고, 그 경우 0살인 것 보다 null로 명시하는 것이 더 좋을 것 같아서 사용했습니다:)
protected Address() { | ||
this(null, null, null); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기는 롬복을 이용한 것이 아닌 이렇게 명시하신 이유가 있으신가요? 학습적인 이유일까요??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
처음에는 @NoArgsConstructor(force = true, access = AccessLevel.PROTECTED)
를 달아줬는데, NoArgsConstructor is only supported on a class or an enum라는 에러가 발생하더라구요🥲
찾아보니 NoArgsConstructor가 record의 디자인 원칙(생성자를 통해 모든 필드를 초기화하는 데이터 전달 객체)과 모순되기 때문에 사용할 수 없다고 합니다.!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오 그런게 있었군요..!😲
그렇다면 드는 생각이 Address는 record에 맞지 않은 객체가 아닌가 싶습니다!
record는 데이터 전달용으로 만들어진 기능이라고 생각하는데NoArgsConstructor가 달릴 수 없는 것이 타당하다고 생각이 들어요. Address가 VO로 사용된 만큼 로직이 생길 수도 있고요.
디자인 원칙과 모순된다고 경고도 줬는데 record를 이렇게 사용하는 것보다 class를 사용하는게 더 맞지 않을까 하는 의견입니다!
@GeneratedValue(strategy = GenerationType.SEQUENCE) | ||
private Long id; | ||
|
||
@Column(name = "order_date_time", columnDefinition = "TIMESTAMP") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개인적인 궁금증인데 혹시 columnDefinition = "TIMESTAMP"가 없다면 이상이 생길까요? 만약 이상이 없다면 TIMESTAMP로 지정하는 이유는 무엇인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
확인해보니 columnDefinition
을 지정하지 않으면 order_date_time이 TIMESTAMP(6)로 생성 되고, 지정하면 TIMESTAMP로 생성이 되더라구요!
columnDefinition
으로 해당 필드 값을 DB에 어떤 타입으로 저장할지 구체적으로 명시할 수 있는 것 같습니다!
그리고 columnDefinition
옵션을 주지 않는다면 JPA가 알아서 적절한 default 값으로 생성하는 것 같습니다!
이 방법을 쓰면 개발자가 원하는 타입으로 데이터베이스에 해당 값을 저장할 수 있다는 장점이 있는 것 같고, 단점으로는 만약 TIMESTAMP를 지원하지 않는 DB를 사용한다면 에러가 발생할 수 있을 것 같습니다!
public Order(String memo, List<OrderItem> orderItems, Customer customer) { | ||
this.orderStatus = OrderStatus.COMPLETED; | ||
this.memo = memo; | ||
this.orderItems = (orderItems == null)? new ArrayList<>() : orderItems; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
실수로 공백이 빠진 것 같습니다!
this.orderItems = (orderItems == null)? new ArrayList<>() : orderItems; | |
this.orderItems = (orderItems == null) ? new ArrayList<>() : orderItems; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
매의눈..바로 고쳤습니당!
properties: | ||
hibernate: | ||
query.in_clause_parameter_padding: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
실수로 탭이 더 들어간 것 같습니다!
properties: | |
hibernate: | |
query.in_clause_parameter_padding: true | |
properties: | |
hibernate: | |
query.in_clause_parameter_padding: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
매의눈..감사합니다🙇🏻♀️
|
||
// then | ||
Optional<Customer> found = customerRepository.findById(saved.getId()); | ||
assertDoesNotThrow(() -> found.get()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isPresent나 isNotEmpty가 아니라 이런 식으로 할 수도 있었군요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assertThat(found).isNotEmpty()
로도 할 수 있군요! 몰랐는데 배워갑니당!
.extracting("name", "nickName", "age", "address", "description") | ||
.containsExactly(customer.getName(), customer.getNickName(), customer.getAge(), customer.getAddress(), customer.getDescription()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오..전 assertJ에 좀 약한데 덕분에 하나 배웠습니다!
📌 과제 설명
스프링부트 JPA 위클리 미션
👩💻 요구 사항과 구현 내용
✅ PR 포인트 & 궁금한 점
커밋 메시지 중
fix: 사용하지 않는 애너테이션 제거
커밋 타입이 fix가 아니라 refactor입니다..😅