쿼리메소드로 해결을 할 수 없는 경우 코딩으로 구현할수가 있다.
기능을 새로 추가 할 수도 있고, 기존 기능을 덮어 쓸 수도 있다.
새로 기능을 추가해보겠다.
그럴려면 임의로 인터페이스를 만들어줘야한다.(이름은 맘대로 하면 된다.)
Post를 가져오는 메서드를 만들어보겠다.
메서드를 정의해주고 나면, 구현체를 만들어줘야한다.(구현체의 이름은 인터페이스의이름에 Impl
을 붙여줘서 만들어야한다.)
@Repository, @Transactional을 붙여주고, 필요로 하는 Bean을 주입받아서 사용해주면 된다.
JPQL을 통해 구현 해줄 수 있다.
Repository에 custom해준 인터페이스를 추가해주면 된다.
이런식으로 만들어준 메서드를 사용할 수 있다.(테스트로 사용해보았다.)
기존 기능을 덮어써보겠다.
delete라는 기능은 원래 존재하는 기능이다. 만약 내가 delete를 또 선언해주면, 중복이된다.
JPA에서 오는 메서드와, 내가 커스텀 해준 메서드가 중복이되면, 스프링 데이터 JPA는커스텀 해준 메서드에 우선 순위를 더 높게준다.
따라서 선언 해 준 다음에 구현해주면, 기존 메서드가 아닌 내가 구현해준 메서드가 실행된다.
이런식으로 테스트해보면 내가 커스텀한 것이 사용되는 것을 볼 수 있다.
위와 같은 코드인 경우, Insert 쿼리와 Select쿼리는 날아가지만 Delete 쿼리는 날아가지 않는다.
왜냐하면, 저 테스트는 한 트랜잭션이기 때문이다.(Roll back)
select 쿼리는 기존 데이터를 가져오는 것이기 때문에, 무조건 호출 되는 것이지만,
insert와 delete는 경우에 따라서 날아가지 않을 수도 있다.
상태를 바꾸는 것이지, 실제로 DB에 바로 반영을 하는 것이 아니기 때문이다.
위와 같은 경우는 insert 밑에 select가 있기 때문에 insert 쿼리가 날아가는 것이다.
만약 순서가 바꼈으면 Roll back에 의해 아에 쿼리를 날리지 않는다.
위의 예시들은 한 타입의 Repository를 커스텀하는 방법이다.
만약, 모든 Repository에 공통적으로 추가하고 싶은 기능이 있거나 덮어쓰고 싶은 기능이 있는 경우도 커스텀 할 수 있는 방법이있다.
JpaRepository를 상속받고, 특정 타입을 지정하지는 않는다.
어떤 Entity가 PersistenceContext에 들어있는지 아닌지를 확인하는 기능을 추가해보겠다.(중간에 사용하는 Repository에는 @NoRepositoryBean를 붙여줘야한다.)
그리고, 구현체를 만들어줘야 한다.(이 경우는 이름에 Impl을 안붙여주고 맘대로 해도된다.)
스프링 데이터 JPA가 지원해주는 가장 밑단에 가장 많은 기능을 가지고 있는 클래스를 상속받는다.(SimpeJpaRepository: JpaRepository의 구현체)
만들어준 인터페이스(MyRepository)를 추가해주고, 메서드를 구현한다.(만약 기존 메서드를 덮어쓰고 싶을 때도 여기서 override해서 구현해주면된다.)
생성자도 만들어줘야한다.(super를 호출할 때 2개의 인자를 넘겨줘야하기 때문)
상위 클래스에서 전달받는 EntityManager도 선언해준다.
마지막으로 Main에서 @EnableJpaRepositories 를 사용해서 커스텀해준 구현체를 설정해주면 된다.
이렇게 해주면 이제 MyRepository를 사용하는 모든 저장소가 contains 메서드를 사용할 수 있게 된다.