복붙노트

[SPRING] 스프링 JPA 저장소 동적 쿼리

SPRING

스프링 JPA 저장소 동적 쿼리

현재 저는 Spring JPA Repository 기본 커스텀 질의를 사용하고 있습니다.

 @Query("SELECT usr FROM User usr  WHERE usr.configurable = TRUE "
              + "AND (" +
                        "lower(usr.name) like lower(:filterText) OR lower(usr.userType.classType.displayName) like lower(:filterText) OR lower(usr.userType.model) like lower(:filterText)"
              +      ")"
              + "")
  public List<User> findByFilterText(@Param("filterText") String filterText, Sort sort);

필터 텍스트가 쉼표로 구분 된 값이 될 때이 쿼리를 수정해야합니다. 그러나 다음과 같은 방식으로 동적 쿼리가되며 어떻게 실행할 수 있습니까?

동적 쿼리를 작성해야합니다.

String sql = "SELECT usr FROM User usr WHERE usr.configurable = TRUE";

for(String word : filterText.split(",")) {
                sql += " AND (lower(usr.name) like lower(:" + word + ") OR lower(usr.userType.classType.displayName) like lower(:" + word + ") OR lower(usr.userType.model) like lower(:" + word + "))";
}

해결법

  1. ==============================

    1.JB Nizet과 스프링 데이터 문서에서는 맞춤 인터페이스 + 저장소 구현을 사용해야한다.

    JB Nizet과 스프링 데이터 문서에서는 맞춤 인터페이스 + 저장소 구현을 사용해야한다.

    메소드를 사용하여 인터페이스를 작성하십시오.

    public interface MyEntityRepositoryCustom {
        List<User> findByFilterText(Set<String> words);
    }
    

    구현 만들기 :

    @Repository
    public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
        @PersistenceContext
        private EntityManager entityManager;
    
        public List<User> findByFilterText(Set<String> words) {
            // implementation below
        }
    }
    

    기존 저장소 인터페이스에서 새 인터페이스를 확장하십시오.

    public interface MyEntityRepository extends JpaRepository<MyEntity, Long>, MyEntityRepositoryCustom {
        // other query methods
    }
    

    마지막으로 메소드를 다른 곳에서 호출하십시오.

    dao.findByFilterText(new HashSet<String>(Arrays.asList(filterText.split(","))));
    

    쿼리 구현

    SQL 변수를 생성하는 방법, 즉 일부 문자열을 쿼리에 연결하는 방법이 좋지 않습니다. 이러지 마.

    연결하는 단어는 유효한 JPQL 식별자, 즉 a : 다음에 Java 식별자 시작, 선택적으로 일부 Java 식별자 부분이 따라야합니다. 즉, CSV에 foo bar, baz가 포함되어있는 경우 foo bar를 식별자로 사용하려고 시도하면 예외가 발생합니다.

    대신 CriteriaBuilder를 사용하여 안전하게 쿼리를 생성 할 수 있습니다.

    public List<User> findByFilterText(Set<String> words) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> q = cb.createQuery(User.class);
        Root<User> user = q.from(User.class);
    
        Path<String> namePath = user.get("name");
        Path<String> userTypeClassTypeDisplayName = 
                         user.get("userType").get("classType").get("displayName");
        Path<String> userTypeModel = user.get("userType").get("model");
        List<Predicate> predicates = new ArrayList<>();
        for(String word : words) {
            Expression<String> wordLiteral = cb.literal(word);
            predicates.add(
                    cb.or(
                        cb.like(cb.lower(namePath), cb.lower(wordLiteral)),
                        cb.like(cb.lower(userTypeClassTypeDisplayName),
                                cb.lower(wordLiteral)),
                        cb.like(cb.lower(userTypeModel), cb.lower(wordLiteral))
                    )
            );
        }
        q.select(doc).where(
                cb.and(predicates.toArray(new Predicate[predicates.size()]))
        );
    
        return entityManager.createQuery(q).getResultList();
    }
    
  2. ==============================

    2.나는 해결책을 찾고 있었다. "Custom"저장소 인터페이스와 implentation의 이름은 매우 엄격합니다 (Spring Data JPA에 사용자 정의 메소드를 추가하는 방법)

    나는 해결책을 찾고 있었다. "Custom"저장소 인터페이스와 implentation의 이름은 매우 엄격합니다 (Spring Data JPA에 사용자 정의 메소드를 추가하는 방법)

    따라서, 전체 코드는 분명합니다. (하지만 @beerbajay가 옳았다)

    커스텀 메소드 인터페이스

    public interface MyEntityRepositoryCustom {
        List<MyEntity> findSpecial();
    }
    

    커스텀 메소드 구현

    public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
        @PersistenceContext
        private EntityManager em;
    
        //custom method implementation
        public List<Object> findSpecial() {
            List<Object> list = em.createNativeQuery("select name, value from T_MY_ENTITY").getResultList();
            return list;
        }
    }
    

    "원래"저장소

    @Repository
    public interface MyEntityRepository extends JpaRepository<MyEntity,Long>, MyEntityRepositoryCustom {
        //original methods here... do not redefine findSpecial()...
    }
    

    새로운 커스텀 메소드로 "원래의"저장소를 사용할 수 있습니다.

    @Service
    public class MyService {
        @Autowired
        private DataRepository r;
    
        public void doStuff() {
            List<Object> list = r.findSpecial();
        }
    }
    
  3. ==============================

    3.스프링 데이터 JPA는 "사양"을 사용하여 사용자 지정 및 동적 쿼리를 만드는 방법을 제공합니다. 스프링 데이터 - 사양

    스프링 데이터 JPA는 "사양"을 사용하여 사용자 지정 및 동적 쿼리를 만드는 방법을 제공합니다. 스프링 데이터 - 사양

    첫째, JPARepository 또는 CRUDRepository를 확장하는 인터페이스는 JpaSpecificationExecutor <...>를 구현해야하며 그게 전부입니다. 저장소에 이제 Specification <...> 객체를 허용하는 findAll이라는 새로운 메소드가 생겼고 Beerbajay 메소드를 toPredicate (...) 메소드를 대체하여 CriteriaQuery를 작성하는 데 사용할 수 있으며 거기에서 빌드 할 수 있습니다 (거의 ) 당신이 원하는 모든 쿼리 :

    사양 <...> spec = 새로운 사양 <...> () {    @보수    public 술어 toPredicate (루트 <...> 엔터티, CriteriaQuery 쿼리, CriteriaBuilder cb) {    목록 <조건> 조건 = buildManyPredicates (cb, 엔티티);    return cb.and (conditions.toArray (new Predicate [conditions.size ()]));    }  }; repository.findAll (spec, PageRequest.of (0, 10));

    이렇게하면 Spring 데이터가 사용자 정의 인터페이스에 추가 한 메소드를 구문 분석하려고하는 문제가 해결됩니다 (사용자 정의 인터페이스가 없으므로).

  4. from https://stackoverflow.com/questions/30431035/spring-jpa-repository-dynamic-query by cc-by-sa and MIT license