ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프로젝트 그린더 Data Jpa 적용 1편
    Project/Greendar 2023. 4. 18. 21:22

    이 글은 프로젝트의 일정은 끝났지만 개인의 학습과 탐구심의 목표를 채우기 위하여 이것 저것을 한 글 입니다. 

     

    관련 깃허브 : 

    https://github.com/Team-Greendar/GreendarServer

     

    GitHub - Team-Greendar/GreendarServer: Greendar Server Repository

    Greendar Server Repository. Contribute to Team-Greendar/GreendarServer development by creating an account on GitHub.

    github.com

     

     

    구글 솔류션 첼린지는 끝났지만 새로운 프로젝트를 하기보다는 서비스를 고도화 시키는 작업 + 기술의 이해을 하고 싶었다.

     

    추가적으로 앞으로는 redis , testCode, 좋은 코드란 무엇인가에 관한 것 또는 "이러이러한 요구사항 또는 문제가 있으면 어떻게 할지"에 관한 해결책들을 한번 적용해볼려고 한다.

     

    도메인의 대한 이해와 객체지향의 이해 , testcode 의 이해및 구현 능력이 좋다면 tdd 를 하겠지만, 그것이 안된다면 (지금의 나) 기존 서비스에 test code 를 추가하고 기존 서비스를 보호 하면서 refactoring 을 들어가는게 맞는 방향인 것 같다(우.형 포비님의 피드백) 

     

     

    리펙 토링의 설명에 앞서 개념을 한번 정리하고 가자.  단순하게  학습의 목적을 위해 dataJpa 를 적용한 글도 물론 훌륭할 수 있지만 ,

    나의 상황과 경험을 고려한 기술도입 배경을 항상 설명을 하는 것이 내가 작성할 또는 변경할 코드의 기본적인 근거가 된다 설명이 가능 할 듯 싶다.

     

    JPA : JPA 는 인터페이스이다(명세서) .  JPA 의 구현체는 다양한 것이 될 수 가 있다.  이 말은 내가 JPA를 사용하기 위하여 기존의 

    Hibernate 와 같은 "프레임워크"를 사용한 것 을 유지할 이유가 없고 마음에 안들면 "바꿔"도 된다. 

     

    라이브러리를 사용하는 애플리케이션 코드는 애플리케이션 흐름을 직접 제어한다.  프레임워크는 거꾸로 애플리케이션 코드가 프레임워크에 의해 사용된다. - 토비의 스프링 참고

     

    Spring Starter의 Data JPA의존성에는 Hibernate 구현체가 기본적으로 포함되어 있다. (알고 쓰자 += 1)

     

    +EntityManager 도 인터페이스 이다 

    다음과 같이 설명이 있으니 시간이 되면 읽어 보자. 

    import javax.persistence.EntityManager;
    public interface EntityManager {
    
        /**
         * Make an instance managed and persistent.
         * @param entity  entity instance
         * @throws EntityExistsException if the entity already exists.
         * (If the entity already exists, the <code>EntityExistsException</code> may 
         * be thrown when the persist operation is invoked, or the
         * <code>EntityExistsException</code> or another <code>PersistenceException</code> may be 
         * thrown at flush or commit time.) 
         * @throws IllegalArgumentException if the instance is not an
         *         entity
         * @throws TransactionRequiredException if there is no transaction when
         *         invoked on a container-managed entity manager of that is of type 
         *         <code>PersistenceContextType.TRANSACTION</code>
         */
        public void persist(Object entity);
        
        /**
         * Merge the state of the given entity into the
         * current persistence context.
         * @param entity  entity instance
         * @return the managed instance that the state was merged to
         * @throws IllegalArgumentException if instance is not an
         *         entity or is a removed entity
         * @throws TransactionRequiredException if there is no transaction when
         *         invoked on a container-managed entity manager of that is of type 
         *         <code>PersistenceContextType.TRANSACTION</code>
         */    
    

     

    그럼 기존의 코드를 보자 ,  이벤트와 관련된 Todo list 의 들어갈 Repository 단이다.

    @Repository
    @RequiredArgsConstructor
    public class EventTodoJpaRepository {
        @PersistenceContext
        private final EntityManager em;
    
        public EventTodo save(Boolean complete, String imageUrl, EventTodoItem eventTodoItem, Member member) {
            EventTodo eventTodo= EventTodo.of(new TodoImage(imageUrl),complete,eventTodoItem,member);
            em.persist(eventTodo);
            return eventTodo;
        }
    
        public EventTodo updateEventTodoComplete(Long eventTodoId, Boolean complete) {
            EventTodo eventTodo = em.find(EventTodo.class, eventTodoId);
            eventTodo.updateComplete(complete);
            em.merge(eventTodo);
            return eventTodo;
        }

     

    보시다시피 , Hibernate 와 같은 ORM 프레임워크 을   활용하면 직접적인 쿼리의 작성 없이 순수 자바 코드 만으로 데이터 베이스와 상호 작용이 가능하다. 

     

    코드에서 수정할 부분은 다음과 같이보인다.

     

    위의 코드에 업데이트 관련을 보자.. em.find()를 하였을때 결과가 없으면 예외 처리를 어떻게 할것인가 ?

    Java 8 에는 Optional 이라는 기능이 생겼으며 , null 을 처리 하는데 도움을 주는 api 이니 활용을 해보자

     

    2. em.merge 를 사용하는것보다는 Jpa 의 변경 감지를 이요하여 코드를 작성하는것이 칼럼에 null 이 들어갈 em.merege 보다 안전할것 같다.

     

        public EventTodo updateEventTodoComplete(Long eventTodoId, Boolean complete) {
            EventTodo eventTodo = em.find(EventTodo.class, eventTodoId);
            eventTodo.updateComplete(complete);
            em.merge(eventTodo);
            return eventTodo;
        }

     

    find 는 하단의 설명과 같이 엔티티가 없으면 null 을 반환한다.

    public <T> T find(Class<T> entityClass, Object primaryKey);
    
    /**
     * Find by primary key, using the specified properties. 
     * Search for an entity of the specified class and primary key. 
     * If the entity instance is contained in the persistence 
     * context, it is returned from there. 
     * If a vendor-specific property or hint is not recognized, 
     * it is silently ignored. 
     * @param entityClass  entity class
     * @param primaryKey   primary key
     * @param properties  standard and vendor-specific properties 
     *        and hints
     * @return the found entity instance or null if the entity does
     *         not exist 
     * @throws IllegalArgumentException if the first argument does 
     *         not denote an entity type or the second argument is
     *         is not a valid type for that entity's primary key or 
     *         is null 
     * @since 2.0
     */

     

    1 . try - catch 문을 이용한다. 

    -> 중복코드가 생길 수 있다.  , 다음 링크는 나처럼 고민한 사람이 있다라는 질문글이다.

    https://stackoverflow.com/questions/28249874/best-practice-for-jpa-with-java8s-optional-return

     

    Best practice for JPA with Java8's Optional return?

    I love Java8's semantics. I use a lot of such code in my DAOs : public Optional<User> findBy(String username) { try { return Optional.of( emp.get().createQuery("select u ...

    stackoverflow.com

    ->@FunctionalInterface 를 사용하여 인터페이스를 적용한후 람다 함수를 만드는 방식은 어떤가 ?

    @FunctionalInterface

    : 다양한 예외처리를 해야하는 상황에서 코드의 변경량이 많아진다.

     

     

    Spring Data JPA 사용 시 Repository에서 리턴 타입을 Optional로 바로 받을 수 있도록 지원한다.

     

     

    목표 :

     

    Spring Data JPA 를 사용하도록 기존 코드에서 변경하자 + (Spring Data JPA 는 update 관련 명명법이 없다)

     

     

     

     

     

    2편에서 계속,,

     

     

     

    'Project > Greendar' 카테고리의 다른 글

    처음으로 회원가입시 생기는 문제  (0) 2023.04.21
    프로젝트 그린더 Data Jpa 적용 2편  (0) 2023.04.18
Designed by Tistory.