JPA Null 처리 방법, List가 null이 아닌 이유
이번에는 자바로 JPA Null 처리하는 방법에 대해 기록하려합니다.
당연하게 db조회시, 객체가 없을경우 null이 발생할 수 있고, 우리는 null을 대비해야만 합니다.
1. Optional
이전에 Java8 부터 등장한 Optional에 대해 포스팅을 한 적이 있습니다.
duooo-story.tistory.com/38?category=881766
JPA에서 단일 엔티티를 조회하는 경우, Optional을 사용하게 되어있습니다. 해당 부분으로 인하여 좀더 우아하게? null을 막을 수 있습니다.
public interface AccountRepository extends JpaRepository<Account,Long> {
Optional<Account> findById(Long id);
}
or
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
Optional<T> findById(ID id);
}
Optional사용법은 위 포스팅을 참고 부탁드립니다.
이번에는 단일 entity가 아닌 List를 받는경우를 살펴보겠습니다.
우선 결과부터 작성하면 List로 받는 객체의 경우, null이 아닌 Empty List가 내려옵니다.
그렇다면 왜 그렇게 내려오는지를 확인하기위해 테스트를 진행하고자 몇가지의 코드를 작성했습니다.
// 1
(CrudRepository) findAll()
public interface AccountRepository extends JpaRepository<Account,Long> {
// 2
List<Account> findByIdGreaterThan(Long id);
// 3
@Query( value = "select myAccount from myAccount a where a.id > 1" ,nativeQuery = true)
List<Account> findAccountList(Long id);
}
1) 우선 기본 CrudRepository 에 있는 findAll을 살펴봤습니다.
기본 findAll 호출시, SimpleJpaRepository를 통해 findAll을 타고 들어가다 보면 다음과 같은 과정을 타게 됩니다.
- CriteriaQueryTypeQueryAdapter 에 있는 getResultList() 호출,
- org.hibernate.loader 에 processResultSet 과정을 통해 빈리스트 리턴
public List<X> getResultList() {
return jpqlQuery.getResultList();
}
-------------------------------------------
protected List processResultSet(
ResultSet rs,
QueryParameters queryParameters,
SharedSessionContractImplementor session,
boolean returnProxies,
ResultTransformer forcedResultTransformer,
int maxRows,
List<AfterLoadAction> afterLoadActions) throws SQLException {
....
final List results = new ArrayList();
....
final boolean debugEnabled = LOG.isDebugEnabled();
for ( count = 0; count < maxRows && rs.next(); count++ ) {
....
Object result = getRowFromResultSet(
rs,
session,
queryParameters,
lockModesArray,
optionalObjectKey,
hydratedObjects,
keys,
returnProxies,
forcedResultTransformer
);
results.add( result );
....
}
....
return results;
}
2) method Keyword를 통해 쿼리를 작성하고 리스트를 가져오는 경우에도 거의 비슷한 경우입니다.
static class CollectionExecution extends JpaQueryExecution {
@Override
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
return query.createQuery(accessor).getResultList();
}
}
public List<X> getResultList() {
return jpqlQuery.getResultList();
}
- JpaQueryExecution에 있는
- 이후 과정 위와 동일
3) 마지막으로 native Query를 이용하여 조회하는 경우, 2)와 동일한 과정을 통하여 결국 빈 리스트를 가져오게 됩니다.
다른 List조회 쿼리 생성방법이 많겠지만, 아마 거의 유사하거나 동일한 과정을 통해 결국 빈값을 가져오리라 생각합니다. 혹시 다른 케이스가 나오신다면 공유..! 부탁드립니다!