ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Kotlin & Spring 으로 Entity 생성하기
    프레임워크/Spring Boot 2024. 7. 1. 21:01

     

    자바로 spring을 시작했는데, 회사에서는 코틀린을 쓰게 되었습니다~

    비슷할 거라고 생각하고 작업을 하지만, 예상치 못한 곳에서 번거로움이 있어서 업무 속도가 안나옵니다! ㅠ

    어떻게 하는게 좋을까 고민을 해보며 글을 적어봅니다!

     


     

    1. 주 생성자를 사용해서 엔티티 생성

    이 방법이 처음 사용한 방법이고 가장 기본적인 방법이라고 생각이 들었습니다.

    @Entity
    @Table(name = "lectures")
    class Lecture(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "lecture_id")
        val lectureId: Long,
    
        @Column(name = "lecture_name", nullable = false, unique = true)
        val name: String,
    
        @Column(name = "lecture_price", nullable = false)
        val price: Int,
    
        @Column(name = "lecture_status", nullable = false)
        private var canRegister: Boolean
    
        ) {
    
        fun getCanRegister(): Boolean {
            return canRegister
        }
    
        fun closeLectureRegistration() {
            this.canRegister = false
        }
    }

     

     

    이렇게 만들고 보니 몇 가지 아쉬운 점이 생깁니다.

     

    1. 일단 캡슐화가 완전하지 않다.

    val로 선언되어서 외부에서 수정은 불가하나, 여전히 접근이 가능하다는 점에서 캡슐화가 깨진 상태라고 보여집니다.

     

    2. 인스턴스를 만들 때, 불필요하게 lectureId를 첫번째 인자로 전달해야된다.

    무의미한 0L을 자리 유지를 위해서 넣어줘야하는 것이 좋지 않아보입니다.

     

     

    2. 캡슐화를 유지하는 방향으로 개선

    모두 private으로 변경하고 getter를 추가해주었습니다.

    @Entity
    @Table(name = "lectures")
    class Lecture(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "lecture_id")
        private val lectureId: Long,
    
        @Column(name = "lecture_name", nullable = false, unique = true)
        private val name: String,
    
        @Column(name = "lecture_price", nullable = false)
        private val price: Int,
    
        @Column(name = "lecture_status", nullable = false)
        private var canRegister: Boolean
    
    ) {
    
        fun getName(): String {
            return name;
        }
    
        fun getLectureId(): Long {
            return lectureId
        }
    
        fun getPrice(): Int {
            return price
        }
    
        fun getCanRegister(): Boolean {
            return canRegister
        }
    
        fun closeLectureRegistration() {
            this.canRegister = false
        }
    }

     

    이번 변경도 여전히 아쉽습니다.

    기존에 있던 2번 문제는 해결되지 않고, 추가로 getter를 잔뜩 작성해줘야하는 문제가 생깁니다.

     

    1. 인스턴스를 만들 때, 불필요하게 lectureId를 첫번째 인자로 전달해야된다. (위에서 언급한 2번 문제)

    무의미한 0L을 자리 유지를 위해서 넣어줘야하는 것이 좋지 않아보입니다.

     

    2. Getter를 직접 작성해주어야한다.

    코틀린이 자바보다 간결한 것이 장점일텐데, 자바 + lombok을 사용하면 적지 않아도 되는 것들을 적게 되는게 좋지 않아보입니다.

     

     

    3. Getter를 간결하게 쓰고, 사용처에서 Named Argument 방식 사용

    조금 개선해보면 아래와 같이 쓸 수 있을 것 같습니다.

    선언측은 lectureId에 기본값을 넣어주고, getter를 조금은 간결하게 작성해줄 수 있습니다.

    @Entity
    @Table(name = "lectures")
    class Lecture(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "lecture_id")
        private val lectureId: Long = 0L,
    
        @Column(name = "lecture_name", nullable = false, unique = true)
        private val name: String,
    
        @Column(name = "lecture_price", nullable = false)
        private val price: Int,
    
        @Column(name = "lecture_status", nullable = false)
        private var canRegister: Boolean
    
    ) {
    
        fun getName(): String = name;
    
        fun getLectureId(): Long = lectureId
    
        fun getPrice(): Int = price
    
        fun getCanRegister(): Boolean = canRegister
    
    
        fun closeLectureRegistration() {
            this.canRegister = false
        }
    }

     

    그리고 사용측은 named argument를 사용해서 lectureId를 넣지 않고 사용할 수 있습니다.

     

     

     

    4. 연관관계를 포함하는 형태로 확장

    그런대로 괜찮아보이는데, 이번에는 조금 더 복잡한 형태를 만들어보겠습니다.

    선생님 엔티티와 연관관계를 형성해줍니다.

    @Entity
    @Table(name = "lectures")
    class Lecture(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "lecture_id")
        private val lectureId: Long = 0L,
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "teacher_id", nullable = false)
        private val teacher: Teacher,
    
        @Column(name = "lecture_name", nullable = false, unique = true)
        private val name: String,
    
        @Column(name = "lecture_price", nullable = false)
        private val price: Int,
    
        @Column(name = "lecture_status", nullable = false)
        private var canRegister: Boolean
    
    ) {
    
        fun getName(): String = name;
    
        fun getLectureId(): Long = lectureId
    
        fun getPrice(): Int = price
    
        fun getCanRegister(): Boolean = canRegister
    
        fun getTeacher(): Teacher = teacher
    
    
        fun closeLectureRegistration() {
            this.canRegister = false
        }
    }

     

    뭔가 실무에서 사용할 때는 연관관계를 갖는 필드가 nullable이 되면서 곤란한 부분들이 생겼는데, 지금은 그런 상황이 발생하지 않는군요

     

     

    5. no-arg 플러그인 추가

    엔티티 클래스는 기본적으로 매개변수가 없는 기본 생성자를 필요로 한다.

    위 코드에는 적어주지 않았기 때문에 생성자를 적으라고 할 것이다.

     

    그럴 땐 no-arg 플러그인을 포함하고 있는 kotlin-jpa 플러그인을 추가해주면된다!

    apply plugin: "kotlin-jpa"

     

     

     

     

     


    https://wslog.dev/kotlin-jpa
    https://spring.io/guides/tutorials/spring-boot-kotlin

Designed by Tistory.