반응형

1:1 관계 예제

  • 1:1 관계는 1:N 관계와 거의 유사
  • 상황 : 영화관에 자리가 여러개 존재하고 고객이 자리를 선택해야 하는 상황
    • 고객은 자리를 하나만 선택할 수 있고, 자리도 한 고객에게만 선택될 수 있는 1:1 관계
    • Customer 객체에는 id와 name 정보가 들어가고, Seat 객체에는 id, rowId(AC), colId(15) 정보가 들어감
    • 각각의 id가 primary key(기본키)로 지정
  • 연관관계 매핑
    • 1:N 관계에서는 보통 N쪽을 연관관계의 주인으로 지정
    • 1:1 관계에서도 연관관계의 주인을 지정해야 함
    • 어느쪽을 주인으로 지정해도 상관 없지만 보통은 foreign key가 있는쪽을 주인으로 지정
    • 이 예제에서는 아래와 같이 Customer에 foreign key를 가져오고 주인으로 정했음

구현 코드

Customer Entity

  • 위에서 언급했든 Customer을 연관관계 주인으로 지정
  • 연관관계 주인 => @JoinColumn으로 column명 지정
  • @OneToOne => default가 FetchType.EAGER이기 때문에 FetchType.LAZY로 지정
@Entity
@Data
public class Customer {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "customer_id")
    private Long id;

    private String name;

    // 연관관계 매핑
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "seat_id")
    private Seat seat;
}

Seat Entity

  • 연관관계의 주인이 아님 => mappedBy 사용
  • Seat도 마찬가지로 @OneToOne이기 때문에 FetchType.LAZY로 지정
@Entity
@Data
public class Seat {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "seat_id")
    private Long id;

    private String rowId;
    private Integer colId;

    // 연관관계 매핑
    @OneToOne(mappedBy = "seat", fetch = FetchType.LAZY)
    private Customer customer;
}

@PostConstruct를 사용한 초기 데이터 생성

  • Customer 1, 2, 3과 Seat 15개 (A1~C5) 를 추가하고자 함
  • 일일이 DB에 삽입할 수 있지만 @PostConstruct 어노테이션을 사용하여 서버가 실행될 때 데이터를 한 번에 삽입해 줄 수 있음
  • 반복문을 사용하기 때문에 매우 간편
  • 매번 실행할 때마다 추가되기 때문에 DB의 ddl-auto가 create나 create-drop이 아닌 경우 데이터가 중복으로 추가될 수 있으니 주의
@Component
@RequiredArgsConstructor
public class MakeInitData {
    private final CustomerRepository customerRepository;
    private final SeatRepository seatRepository;
    @PostConstruct
    public void makeSeatAndCustomer() {

        for(char rowId = 'A' ; rowId <= 'C' ; rowId ++) {
            for(int colId = 1 ; colId <= 5 ; colId ++) {
                Seat seat = new Seat();
                seat.setRowId(String.valueOf(rowId));
                seat.setColId(colId);
                seatRepository.save(seat);
            }
        }

        for(int i = 1 ; i <= 3 ; i ++) {
            Customer customer = new Customer();
            customer.setName("customer" + i);
            customerRepository.save(customer);
        }
    }
}

초기 데이터 생성 결과

좌석 예약

  • customerId와 seatId를 입력받아 좌석 예약
  • 입력받을 때는 DTO 사용 (DTO 코드 생략)
@PostMapping("/reservation")
public String reservation(@RequestBody ReservationRequest request) {
    Customer customer = customerRepository.findById(request.getCustomerId()).get();
    Seat seat = seatRepository.findById(request.getSeatId()).get();
    customer.setSeat(seat);
    customerRepository.save(customer);
    return String.format("%s 손님 (%s, %d) 좌석 예약 성공", customer.getName(), seat.getRowId(), seat.getColId());
}

좌석 예약 결과

좌석 예약 확인

  • rowId와 colId를 입력받아 해당 좌석이 예약되어 있는지 확인
  • 입력받을 때는 DTO 사용 (DTO 코드 생략)
@GetMapping("/reservation-check")
public String reservationCheck(@RequestBody ReservationCheckRequest request) {
    Seat seat = seatRepository.findByRowIdAndColId(request.getRowId(), request.getColId()).get();
    if(seat.getCustomer() == null) {
        return String.format("(%s, %d) 좌석은 예약되지 않았습니다.", request.getRowId(), request.getColId());
    } else {
        return String.format("(%s, %d) 좌석 예약 손님 : %s", request.getRowId(), request.getColId(), seat.getCustomer().getName());
    }
}

좌석 예약 확인

반응형

↓ 클릭시 이동

복사했습니다!