setter에 관한 이야기

 var 프로퍼티가 public으로 열려있어 setter를 쓸 수 있지만 setter 대신 좋은 이름의 함수(=updateName)을 사용하는 것이 훨씬 clean하다. 하지만 name에 대한 setter는 public이기 때문에 유저 이름 업데이트 기능에서 sette r를 사용할'수도' 있다. (=updateName=setName) 따라서 setter만 private하게 만드는 것이 좋다.

첫 번째 방법(backing property 사용)

내부에서는 _name(언더바name)을 사용해서 이름 값을 바꿀 수 있고 외부에서는 불변이 (val) name에 접근해서 Get할 수 있다.

두 번째 방법(custom setter 이용하기)

위 두 방법 모두 property가 많아질수록 번거롭다. 따라서 setter를 열어는 두지만 사용하지 않는 방법을 선호 -> 팀 컨벤션을 잘 맞추면 된다.

 

생성자 안의 프로퍼티. 클래스 body 안의 프로퍼티

꼭 primary constructor 안에 모든 프로퍼티를 넣어야 할까?

body에 만들어도 잘 동작한다.

추천

  • 모든 프로퍼티를 생성자에 넣거나
  • 프로퍼티를 생성자 혹은 클래스 body 안에 구분해서 넣을 때 명확한 기준이 있거나

JPA와 data class

Entity는 data class를 피하는 것이 좋다.

  • equals, hashCode, toString 모두 JPA Entity와는 100% 어울리지 않는 메서드

위의 경우에서

  • User의 quals가 UserLoanHistory의 equals를 부른다.
  • UserLoanHisoty의 equals가 User의 quals를 부른다.

TIP

Entity가 생성되는 로직을 찾고 싶으면 constructor 지시어를 명시적(임의로)으로 작성하고 추적하자!

단순 Book으로 눌러봤을 때는 모든 class가 나오고 constructor를 임의로 작성하고 내부를 눌러보면 딱 '생성'한 부분만 추적가능하다.

'Back-end > Spring+Kotlin' 카테고리의 다른 글

[Spring -> Kotlin] 리팩토링  (0) 2022.12.11
[Java -> Kotlin] Junit5 Test로 코드 짜기  (0) 2022.11.18

Domain 코드 변경하기

특징 : POJO, JPA Entity 객체

Repository  코드 변경하기

특징 : Spring Bean, 의존성 X

Service 코드 변경하기

특징 : Spring Bean, 의존성 O, 비즈니스 로직

Controller, DTO 코드 변경하기

특징 : Spring Bean, 의존성 O, DTO의 경우 그 숫자가 많음

 

Book 코틀린 변경 코드

https://github.com/WantAirpod/Kotlin/commit/b8b353f373aadc79e978897a7cb428cfc77e49b9#diff-56052074ae54fdd8138685dde12fe0d723909f3890c2de412f408e50e83d42a7

User 코틀린 변경 코드

https://github.com/WantAirpod/Kotlin/pull/5/commits/be811187dfb3deebee2704c859a4f8db54a9e6e3#diff-57400e043967f14691c6a655d55c4fb1c76fca87f7d93601827c3a3b7cadf25a

 

Issue : 코틀린 리플렉션 발생 수정

단순히 java->kotlin으로 코드 변경 시 reflect 이슈가 발생한다.

해결 방법

코틀린 reflect 관련 의존성 주입으로 해결한다.

그 밖에 코틀린을 사용하기 위한 의존성도 있다.

 

코틀린은 null에 대해서 무자비하다. 

https://tourspace.tistory.com/114

 

[Kotlin] 코틀린 null 처리 - ? ?. ?: !!, let, lateinit, 제너릭, 플랫폼 타입

이 글은 Kotlin In Action을 참고 하였습니다.더욱 자세한 설명이나 예제는 직접 책을 구매하여 확인 하시기 바랍니다 코틀린에서는 자바보다 null 처리를 좀더 명확하게 합니다. 따라서 NPE(NullPointerEx

tourspace.tistory.com

 

기능 예시

기능 목록

  • 회원 기능
    • 회원 등록
    • 회원 조회
  • 상품 기능
    • 상품 등록
    • 상품 수정
    • 상품 조회
  • 주문 기능
    • 상품 주문
    • 주문 내역 조회
    • 주문 취소
  • 기타 요구사항
    • 상품은 재고 관리가 필요하다.
    • 상품의 종류는 도서, 음반, 영화가 있다.
    • 상품을 카테고리로 구분할 수 있다.
    • 상품 주문시 배송 정보를 입력할 수 있다.

다대다

  • 관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음
  • 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야함
자체적으로 다대다를 할 수는 있지만 @ManyToMany 하지만 실무에서는 권장하지 않음

회원 한명이 여러 개의 상품을 구매했다고 가정하자. 그렇다면

  • 회원 입장
    • 한 명의 회원이 다양한 상품을 구매할 수있다. 1:n 관계
  • 상품 입장
    • 하나의 상품이 다양한 회원에게 판매 되어 질 수있다.

결론 관계형 데이터 베이스에선 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다. 그렇지만 객체에서는 가능하다.

  • Member 쪽에서 products쪽과 ManyToMany로 연결해준다.

  • Product 쪽에서 JoinTable(Member_product)을 선언하여 링크테이블을 생성해주는 어노테이션을 단다.

  • 자동으로 1:n, n:1 관계를 만드는 것과 같은 원리이다.

오! 편리하다. 생각하고 사용하면 안된다.
- 연결 테이블이 단순히 연결만 하고 끝나지 않는다. (무슨말이지? 단순히 연결만 하고 끝나지 않고 추가 데이터가 들어간다. 별에별게 들어간다. 또한 중간 테이블이 예상할 수가 없다.)
- 주문시간, 수량 같은 데이터가 추가로 들어올 수 있다. (Member_Product에 들어감)

리팩토링

연결 테이블용 엔티티 추가 (연결 테이블을 엔티티로 승격!)

  • Member : 링크 테이블과 연결

  • Product : 링크 테이블과 연결

  • MemberProduct : 링크 테이블 추가
    • count, price, OrderDateTime을 넣을 수 있음

결론
양방향으로 여러개를 가질 수 있을 때 고민해야된다. 주인 한명에 강아지 2개 반대로 강아지 한마리에 주인이 여러명일 경우 우리가 그렇네! 그럴 경우 링크테이블을 걸어야한다.

도메인 모델과 테이블 설계

  1. 회원 <-> 주문 : 회원은 주문을 여러 건 할 수 있기 때문에 1:n의 관계이다.
  2. 주문<-> 배송 : 주문과 배송은 1:1 의 관계이다.
  3. 주문<->상품 : 주문과 상품은 n:n의 관계이다. 왜냐하면 한 번 고객이 한 번 주문 할때 여러 상품을 선택할 수 있기 때문이다.  이런 다대다 관계는 관계형 데이터베이스는 물론이고 엔티티에서도 거의 사용하지 않는다. 따라서 주문상품을 추가하여 주문 <-> 주문상품 <->상품(물품)으로 1:n, n:1로 풀어냈다.

엔티티 설계

  1. 회원(Member) : 이름과 임베디드 타입인 주소(Address), 그리고 주문(orders)리스트를 가진다.
  2. 주문(Order) : 한 번 주문시 여러 상품을 주문할 수 있으므로 주문과 주문상품(OrderItem)을 일대다 관계다.
  3. 주문상품(OrderItem) : 주문한 상품정보와 주문 금액(OrderPrice), 주문수량(count) 정보를 가지고 있다.
  4. 상품(Item) :이름, 가격, 재고수량(stockQuantity)을 가지고 있다. 상품을 주문하면 재고수량이 줄어든다.

테이블 설계

'Back-end > JPA' 카테고리의 다른 글

객체지향 쿼리 언어1 - 기본 문법  (0) 2022.09.24
연관관계 매핑 기초  (0) 2022.08.22
엔티티 매핑  (0) 2022.08.06
[JPA] JPA 영속성 컨텍스트  (0) 2022.05.05
[JPA] Batch Insert  (0) 2022.05.05

목차

    도서관리 어플리케이션 이해하기

    • 우선 자바로 되어있는 코드를 코틀린으로 바꾼다고 생각하면 된다. 하단은 대략적인 프로젝트의 (흔한)플로우이다.

    • localhost:8080/h2-console 접속 및 로그인 정보

    테스트 코드란 무엇인가? 그리고 왜 필요한가?

    • 개발 과정에서 문제를 미리 발견할 수 있다.
    • 기능 추가와 리팩토링을 안심하고 할 수 있다.
    • 빠른 시간 내 코드의 동작 방식과 결과를 확인할 수 있다.
    • 좋은 테스트 코드를 작성하려 하다보면, 자연스럽게 좋은 코드가 만들어 진다.
    • 잘 작성한 테스트는 문서 역할을 한다.(코드리뷰를 돕는다)
    A라는 API는 25개의 다른 로직에 영향을 미친다. 어느날 A라는 API를 수정할 일이 생겼다. 그렇다면...?? 눈물이난다...

    코틀린 코드 작성 준비하기

    • 코틀린 build gradle 생성
    더보기
    plugins {
        id 'org.springframework.boot' version '2.6.8'
        id 'io.spring.dependency-management' version '1.0.11.RELEASE'
        id 'java'
        id 'org.jetbrains.kotlin.jvm' version '1.6.21'
        id 'org.jetbrains.kotlin.plugin.jpa' version '1.6.21'
        id 'org.jetbrains.kotlin.plugin.spring' version '1.6.21'
        id 'org.jetbrains.kotlin.kapt' version '1.6.21'
    }
    
    group = 'com.group'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = '11'
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
        implementation 'org.springframework.boot:spring-boot-starter-web'
    
        implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' // 코틀린을 사용하기 위한 의존성 추가
        implementation 'org.jetbrains.kotlin:kotlin-reflect:1.6.21' // 코틀린을 사용하기 위한 의존성 추가
        implementation 'com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3' // 코틀린을 사용하기 위한 의존성 추가
        implementation 'org.junit.jupiter:junit-jupiter:5.8.1' // 코틀린을 사용하기 위한 의존성 추가
        implementation 'com.querydsl:querydsl-jpa:5.0.0' //querydsl 의존성
        kapt("com.querydsl:querydsl-apt:5.0.0:jpa")
        kapt("org.springframework.boot:spring-boot-configuration-processor")
    
        runtimeOnly 'com.h2database:h2'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
    }
    
    tasks.named('test') {
        useJUnitPlatform()
    }
    
    /**
     * 코틀린에 필요한 compile 옵션 추가
     */
    compileKotlin {
        kotlinOptions {
            jvmTarget = "11"
        }
    }
    
    compileTestKotlin {
        kotlinOptions {
            jvmTarget = "11"
        }
    }

    사칙연산 계산기에 대해 테스트 코드 작성하기

    1. 계산기는 정수만 취급한다.

    2. 계산기가 생성될 때 숫자를 1개 받는다.

    3. 최초 숫자가 기록된 이후에는 연산자 함수를 통해 숫자를 받아 지속적으로 계산한다.

    데이터 클래스로 테스트 코드 검증하기

    더보기

    검증하고자 하는 클래스에 data를 붙여준다.

    package com.group.libraryapp.calculator
    
    import java.lang.IllegalArgumentException
    
    data class Calculator (
        private var number: Int
    ){
    
        fun add(operand: Int){
            this.number += operand
        }
    
        fun minus(operand: Int){
            this.number -= operand
        }
    
        fun multiply(operand: Int){
            this.number *= operand
        }
    
        fun divide(operand: Int){
            if(operand == 0){
                throw IllegalArgumentException("0으로 못나눔")
            }
            this.number /= operand
        }
    }

    메인을 만들어 테스트를 진행한다.

    package com.group.libraryapp.calculator
    
    import java.util.Calendar
    
    /**
     * main 생성
     */
    
    fun main(){
        val calculatorTest = CalculatorTest()
        calculatorTest.addTest();
    }
    class CalculatorTest {
        fun addTest(){
            val calculator = Calculator(5)
            calculator.add(3)
    
            val expectedCalculator = Calculator(8)
            if(calculator != expectedCalculator){
                throw IllegalStateException()
            }
        }
    }

    data를 지우고 number를 public으로 하거나 get을 열어주어 test에서도 접근가능하도록한다.

    코드 컨벤션 _number

    package com.group.libraryapp.calculator
    
    import java.lang.IllegalArgumentException
    
    class Calculator (
        //private var number: Int
        //var number: Int // setter를 연 상태
        private var _number: Int
    
    ){
    
        /**
         * getter를 연상태
         */
        val number: Int
            get() = this._number
    
        fun add(operand: Int){
            this._number += operand
        }
    
        fun minus(operand: Int){
            this._number -= operand
        }
    
        fun multiply(operand: Int){
            this._number *= operand
        }
    
        fun divide(operand: Int){
            if(operand == 0){
                throw IllegalArgumentException("0으로 못나눔")
            }
            this._number /= operand
        }
    }

    test쪽에서 바로 get 가능하다.

    package com.group.libraryapp.calculator
    
    import java.util.Calendar
    
    /**
     * main 생성
     */
    
    fun main(){
        val calculatorTest = CalculatorTest()
        calculatorTest.addTest();
    }
    class CalculatorTest {
        fun addTest(){
            // given
            val calculator = Calculator(5)
    
            //when
            calculator.add(3)
            /*
            val expectedCalculator = Calculator(8)
            if(calculator != expectedCalculator){
                throw IllegalStateException()
            }  */
            //then
            if(calculator.number != 8 ){
                throw  IllegalStateException()
            }
        }
    }

    Junit5 사용법과 테스트 코드 리팩토링

    Junit5에서 사용되는 5가지 어노테이션

    6

    • @Test : 테스트 
    • @BeforeEach : 각 테스트 메소드가 수행되기 전에 실행되는 메소드를 지정한다.
    • @AfterEach : 각 테스트가 수행된 후에 실행되는 메소드를 지정한다.
    • @BeforeAll : 모든 테스트를 수행하기 전에 최초 1회 수행되는 메소드를 지정한다.
    • @AfterAll : 모든 테스트를 수행한 후 최후 1회 수행되는 메소드를 지정한다.

    Test Code 작성

    더보기
    package com.group.libraryapp.calculator
    
    import org.junit.jupiter.api.*
    
    class JunitTest {
        companion object {
            @BeforeAll
            @JvmStatic
            fun beforeAll() {
                println("모든 테스트 시작 전")
            }
    
            @AfterAll
            @JvmStatic
            fun afterAll() {
                println("모든 테스트 종료 후")
            }
        }
    
        @BeforeEach
        fun beforeEach() {
            println("각 테스트 시작 전")
        }
    
        @AfterEach
        fun afterEach() {
            println("각 테스트 종료 후")
        }
    
        @Test
        fun test1() {
            println("테스트 1")
        }
    
        @Test
        fun test2() {
            println("테스트 2")
        }
    }

    결과

    계산기에 적용하기

    assertThat Imort 하기

    • AssertProvider 선택하기

    테스트 코드 작성하기

    @Test
    fun addTest(){
        // given
        val calculator = Calculator(5)
    
        // when
        calculator.add(3)
    
        // then
        assertThat(calculator.number).isEqualTo(7);
    }

    테스트 코드 결과

    추가로 사용하는 단언문

    • isTrue/isFalse : true/false 검증
    // then
    val isNew = true
    assertThat(isNew).isTrue();
    assertThat(isNew).isFalse();
    • hasSize(n) : size 검증 (주로 list의 갯수를 확인)

    • extracting/containsExactlyInAnyOrder : 주어진 컬렉션 안의 Item 들에서 name 이라는 프로퍼티를 추출한 후, 그 값이 A와 B인지를 검증한다.(AnyOrder : 이 때 순서는 중요하지 않다)

    • assertThrows : funtion1 함수를 실행했을 때 liigalArgumentException이 나오는지 검증

    만약 나온다면 message로 던져주는 메서드

    Junit5으로 Spring Boot 테스트 하기

    • Controller - bean 관리 대상이므로 @SpringBootTest로 진행
    • Service - bean 관리 대상이므로 @SpringBootTest로 진행
    • Repository - bean 관리 대상이므로 @SpringBootTest로 진행
    • Domain - bean 관리 대상이 아니므로 @Test 진행

    어떤 계층을 테스트 해야 할까?

    보통은 Service 계층을 테스트한다. 보통 A를 보냈을 때 B가 잘 나오는지, 원하는 로직을 잘 수행하는지 검증할 수 있기 때문이다.

     

    @Autowired 해주기

    class UserServiceTest @Autowired constructor(
        private val userRepository: UserRepository
        ,private val userService: UserService
    ) {

    위처럼 contrructor를 사용해서 한 번에 Autowired 해줄 수 있다.

     

    테스트 코드 작성하기

    1. 사칙연산 테스트 코드 작성

    2. UserTest 작성

    2.1 UserTest 작성(get)

    2.2 UserTest 작성(Delete)

    3. Book관련 Loan 관련 테스트 작성

     

    모든 테스트 Terminal로 실행하는 방법

    ./gradlew test

    결과

    다음과 같이 커버리지도 알 수 있다.

    2번 째 방법

    다음의 test를 눌러 본다. 더 권장 되는 방법으로 어디서 틀렸는지 쉽게 확인 가능하다.

    자바의 표준 기술

    • I.O(Input/Output) 기술
    • Network - TCP, UDP 기술
    • 스레드 - 병렬, 멀티
    • JDBC
    • +++ 배치

    배치 핵심 패턴

    • Read - 데이터베이스, 파일, 큐에서 다량의 데이터를 조회한다.
    • Process - 특정 방법으로 데이터를 가공한다.
    • Write - 데이터를 수정된 양식으로 다시 저장한다.

    배치 시나리오

    • 배치 프로세스를 주기적으로 커밋
    • 동시 다발적인 Job의 배치 처리, 대용량 병렬 처리
    • 실패 후 수동 또는 스케줄링에 의한 재시작
    • 의존관계가 있는 step 여러 개를 순차적으로 처리
    • 조건적 Flow 구성을 통한 체계적이고 유연한 배치 모델 구성
    • 반복, 재시도, Skip 처리

     

        완료여부
    1 스프링 배치 시작 2022.10.30
    2 스프링 배치 도메인 이해  
    3 스프링 배치 실행  
    4 스프링 배치 정크 프로세스  
    5 스프링 배치 반복 및 오류제어  
    6 스프링 배치 멀티 스레드 포로세싱  
    7 스프링 배치 리스너  
    8 스프링 배치 테스트 및 운영  

    개발환경

    • JDK 1.8 이상
    • Spring Boot 2.5.1
    • DB - H2, Mysql
    • IDE - Intellij or STS
    • Maven

    선수지식

    • Spring Boot
    • Spring Data JPA
    • Spring JDBC
    • Mysql
    • Lombok

    'Back-end > SpringBatch' 카테고리의 다른 글

    스프링 배치 시작  (0) 2022.10.30

    목차

      JPA는 다양한 쿼리 방법을 지원

      • JPQL (실무에서는 대부분 여기서 해결 됨)
      • JPA Criteria (망한 스펙 절대 안씀)
      • QueryDSL (실무 사용 권장)
      • 네이티브 SQL
      • JDBC API 직접 사용, MyBatis, SpringJdbcTemplate 함께 사용

      JPQL 소개

      • 가장 단순한 조회 방법
        • EntityManager.find()
        • 객체 그래프 탐색(a.getB().getC())
      • JPA를 사용하면 엔티티 객체를 중심으로 개발
      • 문제는 검색 쿼리
      • 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
      • 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
      • 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요

      JPQL 문법

      String jpql = "select m From Member m where m.name like '%hello%'";
      	List<Member> result = em.createQuery(jpql, Member.class).getResultList();
      List<Member> result = em.createQuery("select m From Member m where m.username like '%hello%'"
                  Member.class).getResultList();

      JPQL의 문제점(동적 쿼리)

      *동적 쿼리 : 필요에 의해 직접 붙히거나 짜르는 쿼리

      String qlString = "select m From Member m";
      
      String username;
      if(username != null){
      	String where ="where m.username like '%kim%'";
          qlString + where;
      }

      위의 코드의 문제점

      • 복잡하다.
      • 휴먼에러가 발생하기가 쉽다.
        • qlString 과 where 의 문자열이 띄어쓰기가 된 건지 여부까지 체크해줘야한다. (오타는 당연하고)

      QueryDSL 소개

      다음과 같이 작성할 수 있다. 위의 단점을 해결 할 수 있다.

      • 기본 코드
      QMember m = QMember.member;
      List<Member> result = queryFactory
      					  .select(m)
                            .from(m)
                            .where(m.name.like("kim")
                            .fetch();
      • 동적 쿼리 사용 코드
      public List<Order> findAllByQuerydsl(OrderSearch ordersearch){
      	return queryFactory
          	   .select(order)
                 .from(order)
                 .join(order.member, member)
                 .where(statusEq(orderSearch), memberNameEq(orderSerarch))
                 .fetch();           
      }
      private BooleanExpression memberNameEq(OrderSearch oderSearch){
      	return hasText(orderSearch.getMemberName()) ? member.name.eq(orderSearch.getMemberName)): null;
      }
      
      private BooleanExpression statusEq(OrderSearch oderSearch){
      	return orderSearch.getMemberName() != null ? order.status.eq(orderSearch.getOrderStatus()):null;
      }

      'Back-end > JPA' 카테고리의 다른 글

      도메인 분석 설계 (N:N 뿌시기)  (0) 2022.11.19
      연관관계 매핑 기초  (0) 2022.08.22
      엔티티 매핑  (0) 2022.08.06
      [JPA] JPA 영속성 컨텍스트  (0) 2022.05.05
      [JPA] Batch Insert  (0) 2022.05.05

      목차

        연관관계 매핑

        객체와 테이블 연관관계 차이를 이해

        객체의 참조와 테이블의 외래 키 매핑

        용어 이해

        • 방향(Direction) : 단방향, 양방향
        • 다중성(Multiplicity) : 다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M) 이해
        • 연관관계의 주인(Owner) : 객체 양방향 연관관계는 관리가 필요(가장 까다로움)

        연관관계가 필요한 이유

        객체지향 설계의 목표는 자율적인 객체들의 협력 공동체를 만드는 것이다.

        예제 시나리오

        • 회원과 팀이 있다.
        • 회원은 하나의 팀에만 소속될 수 있다.
        • 회원과 팀은 다대일 관계이다. (회원은 여러명이고, 팀은 1개이다.)

        객체를 테이블에 맞추어 모델링

        (연관관계가 없는 객체)

        Member는 N이며 TEAM은 1이다.

        @Entity
        public class Member {
        	@Id
        	@Column(name = "MEMBER_ID")
        	private String id;
        	private String username;
        	
        	//연관관계 매핑
        	@ManyToOne
        	@JoinColumn(name="TEAM_ID")
        	private Team team;
        	
        	//연관관계 설정
        	public void setTeam(Team team) {
        		this.team = team;
        	}
        	//Getter, Setter ...
        }
        @Entity
        public class Team {
        	@Id
        	@Column (name = "TEAM_ID")
        	private String id;
        	
        	private String name;
        	//Getter, Setter ...
        }
        Team team = new Team();
        team.setName("TeamA");
        em.persist(team);
        
        //Member
        Member member = new Member();
        member.setUsername("member1");
        member.setTeamId(team.getId()); //여기서 이상함
        em.persist(member);
        
        //문제가 많은 find하기
        Member findMember = em.find(Member.class, member.getId());
        Long findTeamId = findMember.getTeamId();
        Team findTeam = em.find(Team.class, findTeamId);

        위의 코드에서 문제점은 findMember를 memberId로 조회하고 그 조회한 내용 중에 TeamId를 가져와서 Team을 또 조회한다.

        Join으로 협력관계가 있는게 아닌 Select를 두 번 하는 꼴

        객체를 테이블에 맞추어 데이터 중심으로 모델링하면, 협력 관계를 만들 수 없다.

        객체 지향 모델링

        위의 모델링과 다른 점은 TeamId가 아닌 Team을 모델링 했다는 점이다.

        @Entity
        public class Member {
        	@Id
        	@Column(name = "MEMBER_ID")
        	private String id;
        	private String username;
        	
        	//연관관계 매핑
        	@ManyToOne
        	@JoinColumn(name="TEAM_ID")
        	private Team team; //가장 중요
        	
        	//연관관계 설정
        	public void setTeam(Team team) {
        		this.team = team;
        	}
        	//Getter, Setter ...
        }

        @ManyToOne

        Member 입장 에서 N이고 Team이 1이기 때문에 ManyToOne이다. 

        Team team = new Team();
        team.setName("TeamA");
        em.persist(team);
        
        //Member
        Member member = new Member();
        member.setUsername("member1");
        //member.setTeamId(team.getId()); //여기서 이상함
        member.setTeam(team);
        em.persist(member);
        
        //문제가 많은 find하기
        Member findMember = em.find(Member.class, member.getId());
        //Long findTeamId = findMember.getTeamId();
        //Team findTeam = em.find(Team.class, findTeamId);
        Team findTeam = findMember.getTeam();

        위의 findMember는 select 문이 join문으로 알아서 해준다.

        'Back-end > JPA' 카테고리의 다른 글

        도메인 분석 설계 (N:N 뿌시기)  (0) 2022.11.19
        객체지향 쿼리 언어1 - 기본 문법  (0) 2022.09.24
        엔티티 매핑  (0) 2022.08.06
        [JPA] JPA 영속성 컨텍스트  (0) 2022.05.05
        [JPA] Batch Insert  (0) 2022.05.05

        + Recent posts