jpa CrudRepository 사용 시 조건 검색으로 인해 난감한 상황이 생겼다.
예를 들어 사용자 이름, 사용자 이름과 주소, 사용자 이름과 주소와 이메일과 같은 조건으로 검색이 필요 시 조건에 따라 method를 생성해 주어야 한다는 것이었다.

1
2
3
findByName  
findByNameAndAddress
findByNameAndAddressAndEmail

검색 조건이 많아질수록 노가다가 더욱 필요한 부분인 것이다.

그러다 발견한 것이 Specification이다.
CrudRepository 조건 검색을 통한 조회 시 내부적으로 Specification을 이용해 조회가 된다고 봐도 무방하다. SimpleJpaRepository를 참고하기 바란다.

Specification을 사용하기 위해서는 Repository에 JpaSpecificationExecutor를 상속받아야 한다.

1
2
3
4
public interface TblRepository 
extends JpaRepository<TblEntity, Long>, JpaSpecificationExecutor<TblEntity> {
...
}

그럼 사용할 Specification을 작성해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Filter {
public static Specification<TblEntity> list(Map<String, String> search) {
return (root, query, builder) -> {
// join
Join<TblEntity, Tbl2Entity> joinTbl2 = root.join("tbl2", JoinType.LEFT);


search.forEach((key, value) -> {
filters.add(builder.equal(root.get(key).as(String.class), value));
});

return builder.and(filters.toArray(new Predicate[0]));
};
}
}

마지막 목록을 조회해보자.

1
List<TblEntity> lists = tblRepository.findAll(Filter.list(search));

혹시 join table 존재 시 fetchType.Lazy로 인해 n+1 쿼리가 발생하는 경우 repository에 EntityGraph를 적용해보자.

1
2
@EntityGraph(attributePaths = {"tbl2"})
List<TblEntity> findAll(Specification<TblEntity> spec);