2010-02-17 1 views
16

나는 정적 쿼리를 위해 JPA에서 Named Queries라는 아이디어를 좋아하지만, 종종 쿼리의 카운트 결과와 일부 쿼리의 결과 목록을 얻고 싶다. 차라리 두 개의 거의 동일한 NamedQuery를 작성하지 않을 것입니다.결과 세트가있는 JPA Named Query의 카운트 크기를 가져 오는 방법이 있습니까?

@NamedQuery(name = "getAccounts", query = "SELECT a FROM Account") 
. 
. 
    Query q = em.createNamedQuery("getAccounts"); 
    List r = q.setFirstResult(s).setMaxResults(m).getResultList(); 
    int count = q.getCount(); 

은 그럼 m이들 0 및 계정 400 개 행이, 10 가정 해 봅시다 : 이상적으로, 내가 가지고 싶은 것은 같은입니다. 나는 그 안에 10 개의 아이템 목록을 가지고 있다고 생각 하겠지만, 총 400 개의 행이 있다는 것을 알고 싶습니다. 나는 두 번째 @NamedQuery 작성할 수

@NamedQuery(name = "getAccountCount", query = "SELECT COUNT(a) FROM Account") 

을하지만 DRY 위반이 항상 단지 수를 원하는거야 경우 그렇게 할 것으로 보인다. 이 간단한 경우에는 두 항목을 동기화 상태로 유지하는 것이 쉽지만 쿼리가 변경되면 값을 줄이기 위해 @NamedQueries를 모두 업데이트해야한다는 것이 이상적이지 않습니다.

일반적인 사용 사례는 항목의 일부 하위 집합을 가져 오는 것이지만 총 개수 ("1-10/400 표시 중")를 나타내는 방법이 필요합니다. setFirstResult/setMaxResults 결과 집합의 부분 집합을 반환하지 않는 사용

답변

13

그래서 결국 두 개의 @NamedQuerys (결과 집합과 카운트 용)를 만들지 만 기본 문자열을 정적 문자열로 캡처하여 DRY를 유지하고 두 쿼리가 일관되게 유지되도록합니다. 따라서 위, 나는이 같은 거라고 :이 예와 분명히

@NamedQuery(name = "getAccounts", query = "SELECT a" + accountQuery) 
@NamedQuery(name = "getAccounts.count", query = "SELECT COUNT(a)" + accountQuery) 
. 
static final String accountQuery = " FROM Account"; 
. 
    Query q = em.createNamedQuery("getAccounts"); 
    List r = q.setFirstResult(s).setMaxResults(m).getResultList(); 
    int count = ((Long)em.createNamedQuery("getAccounts.count").getSingleResult()).intValue(); 

를 쿼리 몸은 사소한 이것은 과잉이다. 그러나 훨씬 더 복잡한 쿼리를 사용하면 쿼리 본문에 대한 단일 정의가 끝나고 두 쿼리를 동기화 할 수 있습니다. 또한 쿼리를 미리 컴파일하고 적어도 Eclipselink를 사용하면 쿼리를 호출 할 때가 아니라 시작시 유효성 검사를받을 수 있다는 장점이 있습니다.

두 쿼리간에 일관된 명명을 사용하면 쿼리의 기본 이름을 기반으로 두 세트를 모두 실행하도록 코드 본문을 래핑 할 수 있습니다.

+0

마지막으로 namedQueries에 대한 작업 해결 방법도 있습니다! 감사합니다. – Zavael

+0

흥미롭게도, 주석을 구성 할 때 정적 결승을 참조 할 수 있다는 것을 알지 못했습니다. 그러나 두 개의 별도의 명명 된 쿼리가 필요하지 않은 솔루션이 여전히 이상적이라고 생각합니다. – aroth

5

가 쿼리도 이러한 방법을 호출 할 때 실행되지 않은, 그들은 getResultList를 호출 할 때 실행됩니다 생성 된 SELECT 쿼리에 영향을 미칩니다. 총 레코드 수를 얻으려면 엔티티를 별도의 쿼리로 (보통 페이지 매기기 전에) SELECT COUNT해야합니다.

완전한 예를 보려면 Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs을 확인하십시오.

+0

예. 쿼리 전체 결과를 얻고 싶습니다. 그래서 예제에서 count는 r.size()와 일치하지 않거나 그냥 사용합니다. 잠재적 인 유스 케이스는 리스팅 계정에 대한 결과 페이지를 얻고 싶지만, 얼마나 많은 페이지가 합계되도록하기 위해서, 나는 단지 25 개의 결과를 검색하고 있지만 쿼리의 총 수를 원할 것입니다. – Tim

+0

@Tim 나는 나의 대답을 분명히했습니다. 여전히 명확하지 않으면 알려주세요. –

+0

감사합니다. 나는 내 질문을 명확히하려고 노력했다. 기본적으로, 수정자를 실행하기 전에 쿼리가 변경된다는 것을 알고 있습니다. 내가하고 싶은 일은 하나의 @NamedQuery를 가지고 하위 집합을 반환하고 카운트를 얻는 대신 하나의 쿼리를 작성하고 반환 세트를 하나씩 작성하는 것입니다. @NamedQuery를 사용하는 것이 이상적입니다. 내가 참조한 링크를 확인해 보겠습니다. – Tim

1

오 잘 같이 명명 된 쿼리 주석을 얻기 위해 자기 반성을 사용할 수 있습니다

String getNamedQueryCode(Class<? extends Object> clazz, String namedQueryKey) { 
    NamedQueries namedQueriesAnnotation = clazz.getAnnotation(NamedQueries.class); 
    NamedQuery[] namedQueryAnnotations = namedQueriesAnnotation.value(); 

    String code = null; 
    for (NamedQuery namedQuery : namedQueryAnnotations) { 
     if (namedQuery.name().equals(namedQueryKey)) { 
      code = namedQuery.query(); 
      break; 
     } 
    } 

    if (code == null) { 
     if (clazz.getSuperclass().getAnnotation(MappedSuperclass.class) != null) { 
      code = getNamedQueryCode(clazz.getSuperclass(), namedQueryKey); 
     } 
    } 

    //if not found 
    return code; 
} 
+0

내 질문에 이것이 어떻게 적용되는지 잘 모르겠습니다. 프리 컴파일, 캐싱 및 기타 최적화의 이점으로 NamedQuery를 사용하고자합니다. 두 개의 쿼리가 하나의 결과를 반환하고 하나가 개수를 반환하는 경우를 제외하고는 동일하게 설정합니다. 그리고 나는 DRY를 따르고 조건절을 복사하고 붙여 넣기를 원치 않습니다. – Tim

관련 문제