[JPA] Custom Repository ๋งŒ๋“ค๊ธฐ

์ €๋ฒˆ์— ์˜ฌ๋ฆฐ ํฌ์ŠคํŒ… ์„ค๋ช…์ด ๋„ˆ๋ฌด ๋ถˆ์ถฉ๋ถ„ํ•˜๊ณ  ๋‚ ๋ฆผ๐Ÿ˜”์ด๋ผ์„œ, ์ƒˆ๋กญ๊ฒŒ ์ •๋ฆฌ. ๊ธฐ์กด์˜ JpaRepository๋ฅผ ์ƒ์†๋ฐ›์•„์„œ ๊ธฐ๋ณธ์ ์ธ CRUD ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‚ด๊ฐ€ 1)์ปค์Šคํ…€ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์™€ ์ด๋ฏธ JpaReposptry์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ƒˆ๋กญ๊ฒŒ 2)์˜ค๋ฒ„๋ผ์ด๋”ฉํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž .

1. ๊ธฐ๋ณธ Post ์—”ํ‹ฐํ‹ฐ, ๋ ˆํฌ์ง€ํ† ๋ฆฌ

@Data
@Entity
@Table
public class Post {

    @Id
    @GeneratedValue
    private Long id;
    private String title;
}
public interface PostRepository extends JpaRepository<Post, Long> {

2. ์ปค์Šคํ…€ํ•œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋งŒ๋“ค๊ธฐ

Customํ•œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ ๋‹ค. ์ด๋ฆ„์€ ์ƒ๊ด€์ด ์—†๋‹ค ์•„๋ฌด๋ ‡๊ฒŒ๋‚˜ ๋งŒ๋“ค์–ด๋„ ๋œ๋‹ค.
PostCustomRepository๋ผ๊ณ  ๋งŒ๋“ฌ. Post๋ชฉ๋ก์„ ๊ฐ€์ง€๊ณ  ์˜ค๋Š” findMyPost() ํ•จ์ˆ˜๋กœ ์ •์˜ํ•จ

public interface PostCustomRepository {

    List<Post> findMyPost();
}

3. ์ปค์Šคํ…€ํ•œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๊ตฌํ˜„ํ•˜๊ธฐ

@Repository
@Transactional
public class PostCustomRepositoryImpl implements PostCustomRepository {

    @Autowired
    EntityManager entityManager;

    @Override
    public List<Post> findMyPost() {
        System.out.println("===== Post Custom Repository ===="); // ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ print
        List<Post> resultList = entityManager.createQuery("SELECT p FROM Post AS p", Post.class).getResultList();
        return resultList;
    }

}

@Repository, @Transactional๋ฅผ ์ด์šฉํ•ด ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ , ํŠธ๋žœ์žญ์…˜ ํ™œ์„ฑํ™”๋ฅผ ์‹œ์ผœ์ค€๋‹ค. entityManger๋ฅผ ํ†ตํ•ด์„œ JPQL ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค์—ˆ์ง€๋งŒ, JdbcTemplate๋ฅผ ์ด์šฉํ•ด์„œ ์ง์ ‘์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค. ์ง€๊ธˆ์€ Type-safe ํ•˜์ง€ ์•Š์€ ์ฟผ๋ฆฌ์ด์ง€๋งŒ ๋‚˜์ค‘์—QueryDsl๋ฅผ ํ†ตํ•ด์„œ ์ฟผ๋ฆฌ๋ฌธ์„ ์ฝ”๋”ฉํ•˜๋“ฏ์ด ์งค ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

public interface PostRepository extends JpaRepository<Post, Long>, PostCustomRepository {
}

๊ธฐ์กด์— PostRepository ์ธํ„ฐํŽ˜์ด์Šค์— ์ปค์Šคํ…€ํ•˜๊ฒŒ ๋งŒ๋“  ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด JpaRepository๋ฅผ ํ†ตํ•ด์„œ ๊ธฐ๋ณธ์ ์ธ CRUD๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ฌผ๋ก , ๋‚ด๊ฐ€ ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“  findMyPost() ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

4. ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค

@RunWith(SpringRunner.class)
@DataJpaTest
public class JpaTest {

    @Autowired
    private PostRepository postRepository;

        private Post createPost() {
        Post post = new Post();
        post.setTitle("new post");
        return postRepository.save(post);
    }

      @Test
    public void postCustomRepositoryTest() {
        Post post = createPost(); // post๋งŒ๋“œ๋Š” ๋™์ž‘

          // ์ปค์Šคํ…€ํ•˜๊ฒŒ ๋งŒ๋“  ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์ž!
        List<Post> myPost = postRepository.findMyPost();
        System.out.println(myPost);
    }
}

ํ…Œ์ŠคํŠธ๋Š” @DataJpaTest Jpa๊ด€๋ จ ๋นˆ๋“ค๋งŒ ๋“ฑ๋กํ•˜๋Š” ์Šฌ๋ผ์ด์‹ฑ ํ…Œ์ŠคํŠธ๋ฅผ ํ•œ๋‹ค.

...
===== Post Custom Repository ====
2019-03-30 13:24:22.088  INFO 53165 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate:
    insert
    into
        post
        (title, id)
    values
        (?, ?)
Hibernate:
    select
        post0_.id as id1_2_,
        post0_.title as title2_2_
    from
        post post0_

[Post(id=1, title=new post, comments=[])]
...

๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด, ๋‚ด๊ฐ€ ๋งŒ๋“  findMyPost()๊ฐ€ ์ž˜ ๋™์ž‘ํ•˜๊ณ  ๊ฒฐ๊ณผ ๊นŒ์ง€ ์ž˜ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธ ํ–ˆ๋‹ค.

#

์ด๋ฒˆ์—๋Š” ๊ธฐ์กด์— JpaRepository๊ฐ€ ์ œ๊ณตํ•˜๋Š” CRUD์—์„œ ๋‚ด๊ฐ€ ์ƒˆ๋กญ๊ฒŒ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€ ์•Œ์•„ ๋ณด์ž. ์œ„์˜ ์˜ˆ์ œ๋ฅผ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•œ๋‹ค.

1. ์ปค์Šคํ…€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•˜๊ณ  ์‹ถ์€ ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€

public interface PostCustomRepository<T> {

    List<Post> findMyPost();

      void delete(T entity);
}

delete ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณด์ž.

2. ์ปค์Šคํ…€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๊ตฌํ˜„

@Repository
@Transactional
public class PostCustomRepositoryImpl implements PostCustomRepository<Post> {


        ...
    @Override
    public void delete(Post post) {
        System.out.println(" ===== Custom Repository delete ======");
        entityManager.remove(post);
    }

๊ธฐ์กด์— Generic ๋ถ€๋ถ„์ด ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, Post๋กœ ์—”ํ‹ฐํ‹ฐ ํƒ€์ž…์„ ์„ค์ •ํ•œ๋‹ค.

public interface PostRepository extends JpaRepository<Post, Long>, PostCustomRepository<Post> {
}

์—ญ์‹œ๋‚˜ ๋˜‘๊ฐ™์ด PostRepository์—์„œ ์ปค์Šคํ…€ํ•˜๊ฒŒ ๋งŒ๋“  ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ƒ์†๋ฐ›์•„์„œ ์‚ฌ์šฉํ•œ๋‹ค. (Generic ์ถ”๊ฐ€)

3. ํ…Œ์ŠคํŠธ

@RunWith(SpringRunner.class)
@DataJpaTest
public class JpaTest {

    @Autowired
    private PostRepository postRepository;

        private Post createPost() {
        Post post = new Post();
        post.setTitle("new post");
        return postRepository.save(post);
    }

      @Test
    public void postCustomRepositoryTest() {
        Post post = createPost();

          postRepository.delete(post);
    }
}
...
===== Custom Repository delete ======
...

๋‚ด๊ฐ€ ์ •์˜ํ•œ ๋ฉ”์„œ๋“œ๋กœ ์ž˜ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ๋จ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ์ปค์Šคํ…€ํ•œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ณ , ๊ตฌํ˜„ํ•  ๋•Œ impl ๋„ค์ด๋ฐ์„ ๊ผญ์ง€์ผœ์•ผ ํ•œ๋‹ค. ์ด ๋ถ€๋ถ„์„ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์œผ๋กœ ๋ฐ”๊พธ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฃจํŠธ์—์„œ repositoryImplementationPostfix ์†์„ฑ์˜ ๊ธฐ๋ณธ๊ฐ’์ด Impl ๋กœ ๋˜์–ด ์žˆ๋‹ค. ์ด ๋ถ€๋ถ„์„ ์ž๊ธฐ๊ฐ€ ์›ํ•˜๋Š” ๋„ค์ด๋ฐ์œผ๋กœ ๊ณ ์น˜๋ฉด ๋œ๋‹ค. Default๋กœ ํฌ์ŠคํŠธํ”ฝ์Šค(์ ‘๋ฏธ์–ด) ๋ฅผ ์ •ํ–ˆ๋‹ค.

@SpringBootApplication
@EnableJpaRepositories(repositoryImplementationPostfix = "Default")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

๊ธฐ์กด์˜ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ๋Œ๋ฆฌ๋ฉด, ๊ตฌํ˜„์ฒด์˜ ๋„ค์ด๋ฐ ๊ทœ์น™์„ ์–ด๊ฒผ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๋Š” ์˜ˆ์™ธ๊ฐ€ ๋‚œ๋‹ค.

Caused by: org.springframework.data.mapping.PropertyReferenceException: No property findMyPost found for type Post!

๊ธฐ์กด์˜ PostCustomRepositoryImpl -> PostCustomRepositoryDefault ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ํ…Œ์ŠคํŠธ์ผ€์ด์Šค๊ฐ€ ์ •์ƒ ๋™์ž‘ํ•œ๋‹ค.

์ •๋ฆฌ

์ปค์Šคํ…€ํ•˜๊ฒŒ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ณ (์ธํ„ฐํŽ˜์ด์Šค) ๊ตฌํ˜„ ํ•˜๋Š” ๊ฒƒ์„ ์ •๋ฆฌํ–ˆ๋‹ค. ๊ตฌํ˜„์€ ๋„ค์ด๋ฐ๊ทœ์น™(default = Impl)๋ฅผ ์ง€์ผœ์•ผ ํ•œ๋‹ค. ์‹ค๋ฌด์—์„œ๋Š” QueryDsl๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ๊ตฌํ˜„๋ถ€์—์„œ jpql์ด ์•„๋‹Œ querydsl๋กœ ๋งŒ๋“ค์–ด์„œ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฐ๊ด€ ํฌ์ŠคํŠธ