- Specification
- Auditing
Specification
query DSL 과 유사하게 query 를 프로그램으로 작성할 수 있도록 해준다. 아래는 JPA 공식 문서에서 Specification 에 대해 설명한 글 일부다.
JPA 2 introduces a criteria API that you can use to build queries programmatically. By writing a criteria, you define the where clause of a query for a domain class. Taking another step back, these criteria can be regarded as a predicate over the entity that is described by the JPA criteria API constraints.
cf. criteria 라는 단어의 뜻 자체가 ‘기준’의 이미이다.
query dsl 과 차이나는 점은 다이나믹 쿼리의 형태로도 Specification 을 사용할 수 있다는 것이다. 나는 개인적으로 이 부분이 제일 마음에 들었다.
사용 방법은 공식문서에도 나와있지만 간단하다. repository 에서 JpaSpecificationExecutor
public interface PostRepository extends JpaRepository<Post, Long>, PostCustomRepository, QuerydslPredicateExecutor<Post>, JpaSpecificationExecutor<Post> {
}
public static Specification<Post> getPostsByCustomSpecification(String name, String description) {
return ((root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>(); // javax.persistence.criteria.Predicate;
if (name != null) {
predicates.add(criteriaBuilder.equal(root.get("name"), name));
}
if (description != null) {
predicates.add(criteriaBuilder.equal(root.get("description"), description));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
});
}
@Test
void specificationTest() {
Post post = new Post();
final String NAME = "specificationPostName";
final String DESCRIPTION = "specificationPostDescription";
post.setName(NAME);
post.setDescription(DESCRIPTION);
postRepository.save(post);
List<Post> targets = postRepository.findAll(Post.getPostsByCustomSpecification(NAME, DESCRIPTION));
Assertions.assertThat(targets.size()).isEqualTo(1);
Assertions.assertThat(targets.get(0).getName()).isEqualTo(NAME);
Assertions.assertThat(targets.get(0).getDescription()).isEqualTo(DESCRIPTION);
}
select
post0_.id as id1_0_,
post0_.description as descript2_0_,
post0_.name as name3_0_
from
post post0_
where
post0_.name=?
and post0_.description=?
# binding parameter [1] as [VARCHAR] - [specificationPostName]
# binding parameter [2] as [VARCHAR] - [specificationPostDescription]
만약 여기서 아래와 같이 DESCRIPTION 에 null 을 넣을 경우 쿼리가 의도한대로 달라진다.
@Test
void specificationTest() {
Post post = new Post();
final String NAME = "specificationPostName";
final String DESCRIPTION = "specificationPostDescription";
post.setName(NAME);
post.setDescription(DESCRIPTION);
postRepository.save(post);
List<Post> targets = postRepository.findAll(Post.getPostsByCustomSpecification(NAME, null));
Assertions.assertThat(targets.size()).isEqualTo(1);
Assertions.assertThat(targets.get(0).getName()).isEqualTo(NAME);
Assertions.assertThat(targets.get(0).getDescription()).isEqualTo(DESCRIPTION);
}
select
post0_.id as id1_0_,
post0_.description as descript2_0_,
post0_.name as name3_0_
from
post post0_
where
post0_.name=?
Auditing
특별한 내용은 없어서 강의자료만 첨부한다.
사용법
- 메인 애플리케이션 위에 @EnableJpaAuditing 추가 (스프링부트가 자동설정 해주지 않는다)
- 엔티티 클래스 위에 @EntityListeners(AuditingEntityListener.class) 추가
@CreatedDate
private Date created;
@LastModifiedDate
private Date updated;
@CreatedBy
@ManyToOne
private Account createdBy;
@LastModifiedBy
@ManyToOne
private Account updatedBy;