스프링 데이터 JPA-10.커스텀 리포지토리, 기본 레포지토리 커스터마이징(스프링 데이터 Common)
스프링 데이터 Common: 커스텀 리포지토리
쿼리 메소드(쿼리 생성과 쿼리 찾아쓰기)로 해결이 되지 않는 경우 직접 코딩으로 구현 가능.
- 스프링 데이터 리포지토리 인터페이스에 기능 추가.
- 스프링 데이터 리포지토리 기본 기능 덮어쓰기 가능.
- 구현 방법
- 커스텀 리포지토리 인터페이스 정의
- 인터페이스 구현 클래스 만들기 (기본 접미어는 Impl)
- 엔티티 리포지토리에 커스텀 리포지토리 인터페이스 추가
기능 추가하기
// 커스텀 레포지토리 (이름 상관없음) but 기본 네이밍 컨벤션을 지켜야 한다. 뒤에 Impl 붙은 클래스 만들어줘야함.
public interface PostCustomRepository {
List<Post> findMyPost();
}
@Repository
@Transactional
public class PostCustomRepositoryImpl implements PostCustomRepository {
@Autowired
EntityManager entityManager;
@Override
public List<Post> findMyPost(){
System.out.println("custom findMyPost");
return entityManager.createQuery("SELECT p FROM Post AS p", Post.class)
.getResultList();
}
}
// JpaRepository도 사용하면서 내가 커스텀한 PostCustomRepository 같이 사용
public interface PostRepository extends JpaRepository<Post, Long>, PostCustomRepository {
}
@ExtendWith(SpringExtension.class)
@DataJpaTest
class PostRepositoryTest {
@Autowired
PostRepository postRepository;
@Test
public void crud(){
postRepository.findMyPost(); // 정상적으로 작동(셀렉쿼리)
}
}
기본 기능 덮어쓰기
// 커스텀 레포지토리 (이름 상관없음) but 기본 네이밍 컨벤션을 지켜야 한다. 뒤에 Impl 붙은 클래스 만들어줘야함.
public interface PostCustomRepository<T> {
List<Post> findMyPost();
void delete(T entity);
}
@Repository
@Transactional
public class PostCustomRepositoryImpl implements PostCustomRepository {
@Autowired
EntityManager entityManager;
@Override
public void delete(Object entity) {
System.out.println("custom delete");
entityManager.remove(entity);
}
..
}
// JpaRepository도 사용하면서 내가 커스텀한 PostCustomRepository 같이 사용
public interface PostRepository extends JpaRepository<Post, Long>, PostCustomRepository<Post> {
}
@ExtendWith(SpringExtension.class)
@DataJpaTest
class PostRepositoryTest {
@Autowired
PostRepository postRepository;
@Test
public void crud(){
Post post = new Post();
post.setTitle("hibernate");
postRepository.save(post);
postRepository.findMyPost();
postRepository.delete(post); // 테스트는 어차피 롤백이라 delete 안함 (굳이 안지워도 없어지니까)
postRepository.flush(); // 강제로 싱크 (removed 상태인 걸 싱크한다는 건 -> delete 쿼리 날린다는 것)
}
}
접미어 설정하기
Impl 쓰기 싫은데?
@SpringBootApplication
@EnableJpaRepositories(repositoryImplementationPostfix = "Default") // Impl 대신
public class Application {
설정 후 Impl 대신 Default 붙이면 된다.
@Repository
@Transactional
public class PostCustomRepositoryDefault implements PostCustomRepository {
@Autowired
EntityManager entityManager;
...
스프링 데이터 Common: 기본 리포지토리 커스터마이징
모든 리포지토리에 공통적으로 추가하고 싶은 기능이 있거나 덮어쓰고 싶은 기본 기능이 있다면
- JpaRepository를 상속 받는 인터페이스 정의
- @NoRepositoryBean
- 기본 구현체를 상속 받는 커스텀 구현체 만들기
- @EnableJpaRepositories에 설정
- repositoryBaseClass
@NoRepositoryBean
public interface MyRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
boolean contains(T entity);
}
public class SimpleMyRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
private EntityManager entityManager;
public SimpleMyRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
@Override
public boolean contains(T entity) {
return entityManager.contains(entity);
}
@Override
public List<T> findAll() {
System.out.println("custom findAll");
return super.findAll();
}
}
@SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = SimpleMyRepository.class)
public class Application {
...
public interface PostRepository extends MyRepository<Post, Long> {
}
@Test
public void crud(){
Post post = new Post();
post.setTitle("hibernate");
assertFalse(postRepository.contains(post));
postRepository.save(post);
assertTrue(postRepository.contains(post));
postRepository.findAll();
}