Develop/spring-data

[JPA] JPA를 적용하며.. ( insert, update 분기 편 )

에디개발자 2020. 11. 27. 07:00
반응형

프로젝트를 진행하면서 JPA를 도입하였습니다. 지난글( [JPA] 프로젝트에 JPA를 적용하며.... ( save편 ) )에서는 JPA의 영속성을 이용하여 insert, update를 처리하는 방법에 대해서 정리하였습니다.  

도입 배경 및 JPA 적용방법에 대해서 궁금하시면 제 블로그에 "JPA" 로 검색하시면 Querydsl, 로깅 처리방법까지 정리해두었습니다.

나를 닮았다고 한다....

insert, update를 메소드로 분리하여 각각 처리하였습니다. 그런데 한 메소드에서 처리할 수 없을까? 하고 고민하고 적용한 내용을 정리하겠습니다. 

 

같은 API로 데이터가 있으면 update하고 없으면 insert하는 메소드 예제를 작성해보겠습니다.

@Service
@RequiredArgsConstructor  // 의존성 주입
public service {

    private final StoreRepository storeRepository;

    @Transactional
    public Store save(final Store store) {
        Optional<Store> storeOptional = storeRepository.findById(store.getId);    // 1)
		Store store;

        if(!storeOptional.isParent()) {    // 2)
            store = new Store();
            store.changeName("용태스토어");
            storeRepository.save(store);
            return store;
        } 
        
        store = storeOptional.get();    // 3)
        store.changeName("용태스토어");
        return store;
    }
}

1) repository에서 조회합니다.

2) 데이터가 없을 경우 Entity 객체를 생성하여 데이터 주입 후 save( insert ) 합니다.

3) 데이터가 있을 경우 데이터 주입 후 return하면 Dirty Checking으로 update 됩니다.

 

음...

음.....

 

소스가 너무 길다. 같은 행위( store.changeName() )을 두번이나 써야할까? 이런 경우 if문 쓰고 분기태워서 매번 이렇게 처리해야하나?? 해서 수정하였습니다. Repository에서 조회한 객체가 null일 경우 save 처리하는 메서드를 생성해보겠습니다.

 

필요한 파라미터는 어떤 것이 있을까??

  • id : insert, update의 기준은 @Id 존재 유무입니다.
public interface StoreRepository extends JpaRepository<Store, Long> {
}
  • repository : 공통 메서드이므로 save 대상이 되는 repository가 필요합니다. repository는 위처럼 JpaRepository에서 상속받기 때문에 JpaRepository repository 이렇게 받으면 됩니다.
  • entity : 마지막으로 저장할 Entity를 받습니다. 

위 파라미터를 종합하여 메서드를 생성해보겠습니다.

public class CommonUtils {
    public static void saveIfNullId(Long id, JpaRepository repository, Object entity) {
        if(id == null) {
            repository.save(entity);
        }
    }
}

Paramter로 id, repository, entity를 받아오고 id가 없으면 repository.save()를 실행합니다.

 

생성한 메서드를 사용하여 위 소스를 수정하겠습니다.

@Service
@RequiredArgsConstructor  // 의존성 주입
public service {

    private final StoreRepository storeRepository;

    @Transactional
    public Store save(final Store store) {
        Store store = storeRepository.findById(store.getId).orElseGet(Store::new);   
        store.changeName("용태스토어");
        CommonUtils.saveIfNullId(store.getId, storeRepository, store);
        return store;
    }
}

훨씬 보기 수월해졌습니다. if 문, 반복 명령문도 제거하였습니다. 이제 저 메서드만 있으면 insert, update 분기처리를 걱정없겠네요 :) 

Data data = (OptionalData).orElseGet(Data::new);
Optional로 감싸진 Data가 null이 아니면 Data 객체에 data가 들어갑니다.
Optional로 감싸진 Data가 null이면 Data 객체에 new Data가 들어갑니다.

더 간단히..
Data data;
if(data == null ) {
    data = new Data();
} else {
    data = data;
}
와 같은 문법입니다.

 

 

 

p.s ) JPA는 아직도 멀었다. 더 공부 공부 공부

반응형