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

[4기 김영주, 소재훈] JPA Mission 3 - 연관관계매핑(order, order_item, item의 연관관계 매핑 실습) #326

Open
wants to merge 11 commits into
base: 영주,재훈-mission
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.programmers.springbootjpa.dto.request;

import com.programmers.springbootjpa.entity.Member;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class CreateRequestDto {

private String name;
private String nickName;
private Integer age;
private String address;

public Member toEntity() {
return Member.builder()
.name(name)
.nickName(nickName)
.age(age)
.address(address)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.programmers.springbootjpa.dto.response;

import com.programmers.springbootjpa.entity.Member;
import lombok.*;

@Getter
@NoArgsConstructor
public class ResponseDto {

private Long memberId;
private String name;
private String nickName;
private String address;

@Builder
private ResponseDto(Long memberId, String name, String nickName, String address) {
this.memberId = memberId;
this.name = name;
this.nickName = nickName;
this.address = address;
}

public static ResponseDto fromEntity(Member member) {
return ResponseDto.builder()
.memberId(member.getId())
.name(member.getName())
.nickName(member.getNickName())
.address(member.getAddress())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.programmers.springbootjpa.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import java.time.LocalDateTime;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public abstract class BaseTimeEntity {

@CreatedDate
@Column(updatable = false)
private LocalDateTime registeredDatetime;

@LastModifiedDate
private LocalDateTime updatedDatetime;
}
49 changes: 49 additions & 0 deletions src/main/java/com/programmers/springbootjpa/entity/Member.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.programmers.springbootjpa.entity;

import jakarta.persistence.*;
import lombok.*;

import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "member")
@Getter
@Setter
jay-so marked this conversation as resolved.
Show resolved Hide resolved
@NoArgsConstructor
public class Member extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@Column(nullable = false, length = 30)
private String name;

@Column(nullable = false, length = 40, unique = true)
private String nickName;

private Integer age;

@Column(nullable = false, length = 100)
private String address;

@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();

@Builder
private Member(String name, String nickName, Integer age, String address) {
this.name = name;
this.nickName = nickName;
this.age = age;
this.address = address;
}

public void addOrder(Order order) {
orders.add(order);
}

public void removeOrder(Order order) {
orders.remove(order);
}
}
47 changes: 47 additions & 0 deletions src/main/java/com/programmers/springbootjpa/entity/Order.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.programmers.springbootjpa.entity;

import com.programmers.springbootjpa.dto.response.ResponseDto;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Entity
@Table(name = "orders")
@Getter
@Setter
public class Order extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@Enumerated(EnumType.STRING)
private OrderStatus orderStatus;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", referencedColumnName = "id")
private Member member;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true)
private List<OrderItem> orderItems = new ArrayList<>();

public void updateMember(Member member) {
if (Objects.nonNull(this.member)) {
this.member.removeOrder(this);
}
this.member = member;
member.addOrder(this);
}

public void addOrderItem(OrderItem orderItem) {
orderItems.add(orderItem);
}

public void removeOrderItem(OrderItem orderItem) {
orderItems.remove(orderItem);
}
}
37 changes: 37 additions & 0 deletions src/main/java/com/programmers/springbootjpa/entity/OrderItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.programmers.springbootjpa.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.Objects;

@Entity
@Table(name = "order_item")
@Getter
@Setter
public class OrderItem extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@Column(nullable = false)
private Integer quantity;

@Column(nullable = false)
private Integer price;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id", referencedColumnName = "id")
private Order order;

public void updateOrder(Order order) {
if (Objects.nonNull(this.order)) {
this.order.removeOrderItem(this);
}

this.order = order;
order.addOrderItem(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.programmers.springbootjpa.entity;

public enum OrderStatus {
ACCEPTED, CANCELED, DELIVERED
Copy link
Member

Choose a reason for hiding this comment

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

문자열 상수로만 이루어져있다해도 한 칸씩 개행해주는 것이 더 가독성에 좋을 것 같다고 생각이 드는데 어떻게 생각하시나요?

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.programmers.springbootjpa.repository;

import com.programmers.springbootjpa.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.programmers.springbootjpa.repository;

import com.programmers.springbootjpa.entity.OrderItem;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderItemRepository extends JpaRepository<OrderItem, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.programmers.springbootjpa.repository;

import com.programmers.springbootjpa.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRepository extends JpaRepository<Order, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.programmers.springbootjpa.service;

import com.programmers.springbootjpa.dto.request.CreateRequestDto;
import com.programmers.springbootjpa.dto.response.ResponseDto;
import com.programmers.springbootjpa.entity.Member;
import com.programmers.springbootjpa.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.NoSuchElementException;

@Service
@RequiredArgsConstructor
public class MemberService {

private final MemberRepository memberRepository;

@Transactional
public void createMember(CreateRequestDto createRequestDto) {
Member member = createRequestDto.toEntity();
memberRepository.save(member);
}

public List<ResponseDto> findAll() {
return memberRepository.findAll().stream()
.map(ResponseDto::fromEntity)
.toList();
}

public ResponseDto findById(Long id) {
Member member = memberRepository.findById(id)
.orElseThrow(() -> new NoSuchElementException("해당 고객이 존재하지 않습니다."));

return ResponseDto.fromEntity(member);
}
Comment on lines +32 to +37
Copy link
Member

Choose a reason for hiding this comment

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

현재 조회 메소드 들에 대해서는 따로 @Transactional(readOnly = true)를 적어주시지 않았는데 따로 이유가 있으실까요?

제가 알기로는 find해서 가져오는 것에는 문제가 없으나 OSIV를 끄고 Member안에 있는 다른 객체의 값을 가져올 때 Lazy Loading이 되지않아 정상적인 동작을 할 수 없는 경우도 있다고 보았습니다!

참고 사항


@Transactional
public void deleteById(Long id) {
if (!memberRepository.existsById(id)) {
throw new NoSuchElementException("삭제하려는 고객을 찾지 못했습니다.");
}

memberRepository.deleteById(id);
}
}
1 change: 0 additions & 1 deletion src/main/resources/application.properties

This file was deleted.

10 changes: 10 additions & 0 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
spring:
datasource:
driver-class-name: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create-drop
database-platform: org.hibernate.dialect.H2Dialect
show-sql: true