Skip to content
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

Open
wants to merge 9 commits into
base: uijin-j
Choose a base branch
from

Conversation

uijin-j
Copy link

@uijin-j uijin-j commented Nov 24, 2023

📌 과제 설명

스프링부트 JPA 위클리 미션

👩‍💻 요구 사항과 구현 내용

  • 미션1 : 단일 엔티티를 이용한 CRUD를 구현
  • 미션2 : customer 엔티티를 이용하여 생명주기 실습
  • 미션3 : order, order_item, item의 연관관계 매핑 실습

✅ PR 포인트 & 궁금한 점

커밋 메시지 중 fix: 사용하지 않는 애너테이션 제거 커밋 타입이 fix가 아니라 refactor입니다..😅

Copy link
Member

@Sehee-Lee-01 Sehee-Lee-01 left a 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AttributeOverrides는 클래스 안의 필드를 컬럼으로 인식하게 해주는 것이군요 👍

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

신기하네요.. 혹시 Address 내부에서 Column을 추가하면 이상이 있을까요? 만약 이상이 없다면 AttributeOverrides를 사용하면서 얻을 수 있는 이점이 무엇인가요??

Copy link
Author

@uijin-j uijin-j Nov 26, 2023

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는 컬럼명을 지정해주고 싶을 때 사용하는 것 같아요:)

Copy link
Author

@uijin-j uijin-j Nov 26, 2023

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를 생략해도 될 것 같네용!

Copy link
Author

@uijin-j uijin-j Nov 26, 2023

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 이건 제가 참고 했던 링크입니다:) 참고해 보셔도 좋을 것 같아요!

Copy link

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;
Copy link
Member

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 설정)이 각각 값 설정이 달라서 이렇게 설정하는 걸로 알고 있어서요! 제가 잘 몰라서 확인차 여쭤봅니당!

Copy link
Author

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로 명시하는 것이 더 좋을 것 같아서 사용했습니다:)

Comment on lines +16 to +18
protected Address() {
this(null, null, null);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 롬복을 이용한 것이 아닌 이렇게 명시하신 이유가 있으신가요? 학습적인 이유일까요??

Copy link
Author

@uijin-j uijin-j Nov 26, 2023

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의 디자인 원칙(생성자를 통해 모든 필드를 초기화하는 데이터 전달 객체)과 모순되기 때문에 사용할 수 없다고 합니다.!

Copy link

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")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

개인적인 궁금증인데 혹시 columnDefinition = "TIMESTAMP"가 없다면 이상이 생길까요? 만약 이상이 없다면 TIMESTAMP로 지정하는 이유는 무엇인가요?

Copy link
Author

@uijin-j uijin-j Nov 26, 2023

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;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실수로 공백이 빠진 것 같습니다!

Suggested change
this.orderItems = (orderItems == null)? new ArrayList<>() : orderItems;
this.orderItems = (orderItems == null) ? new ArrayList<>() : orderItems;

Copy link
Author

@uijin-j uijin-j Nov 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

매의눈..바로 고쳤습니당!

Comment on lines +16 to +18
properties:
hibernate:
query.in_clause_parameter_padding: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실수로 탭이 더 들어간 것 같습니다!

Suggested change
properties:
hibernate:
query.in_clause_parameter_padding: true
properties:
hibernate:
query.in_clause_parameter_padding: true

Copy link
Author

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());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isPresent나 isNotEmpty가 아니라 이런 식으로 할 수도 있었군요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertThat(found).isNotEmpty()로도 할 수 있군요! 몰랐는데 배워갑니당!

Comment on lines +42 to +43
.extracting("name", "nickName", "age", "address", "description")
.containsExactly(customer.getName(), customer.getNickName(), customer.getAge(), customer.getAddress(), customer.getDescription());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오..전 assertJ에 좀 약한데 덕분에 하나 배웠습니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants