2012-05-17 3 views
4

여러 가지 이유로 Criteria API를 사용하지 않고 부분적으로 동적 인 HQL 쿼리를 작성하려고합니다. HQL 표현식을 사용하여 where 제한을 단락시키는 쉬운 방법이 있는지 알고 싶었습니다.Criteria 대신 hql 표현식을 사용하는 동적 HQL 쿼리?

SELECT customer 
FROM Customer as customer 
INNER JOIN customer.profile as profile 
WHERE profile.status IN :statusCodes 
AND profile.orgId IN :orgIds 

StatusCodes은 문자열의 목록이며, orgIds는 정수의 목록입니다 : 예를 들어, 다음은 잘 작동 원래 쿼리입니다. 그러나 둘 중 하나는 선택적이며 콜렉션 대신에 null이 전달되면 제한해서는 안됩니다.

SELECT customer 
FROM Customer as customer 
INNER JOIN customer.profile as profile 
WHERE (:statusCodes IS NULL OR profile.status IN :statusCodes) 
AND (:orgIds IS NULL OR profile.orgId IN :orgIds) 

불행하게도 작동하지 않았다, 그러나 어느 다른 표현을 사용하거나 디폴트 값을 전달 작업을 할 수있는 다른 방법이있다 : 나는과 같이 이러한 목표를 달성하기 위해 노력했습니다?

편집 : 분명히 어떤 식 으로든 동적으로 쿼리를 작성하지 않고 NamedQuery를 사용하는 방법을 찾고 있습니다.

해결 방법 : 추가 쿼리 매개 변수를 사용하여이를 수행했습니다.

private void setRequiredParameter(TypedQuery<?> query, String name, Object value) { 
    query.setParameter(name, value); 
} 

private void setOptionalParameter(TypedQuery<?> query, String name, Object value) { 
    query.setParameter(name, value); 
    query.setParameter(name + "Optional", value == null ? 1 : 0); 
} 

그래서 같은 질의 :

SELECT customer 
     FROM Customer as customer 
     INNER JOIN customer.profile as profile 
     WHERE (:statusCodesOptional = 1 OR profile.status IN :statusCodes) 
     AND (:orgIdsOptional = 1 OR profile.orgId IN :orgIds) 

답변

1

당신이 절대적으로 동적 쿼리를 방지해야하는 경우, 두 개의 추가 매개 변수의 비용으로 수행 할 수 있습니다 : 당신은 다음과 같이 할 것 자바 코드에서

SELECT customer 
    FROM Customer AS customer 
    JOIN customer.profile AS profile 
WHERE (profile.status IN :statusCodes OR :statusCodeCount = 0) 
    AND (profile.orgId IN :orgIds OR :orgIdCount = 0) 

:

session.getNamedQuery("your.query.name") 
     .setParameterList("statusCodes", statusCodes) 
     .setParameter("statusCodeCount", statusCodes.length) 
     .setParameterList("orgIds", orgIds) 
     .setParameter("orgIdCount", orgIds.length); 

을 당신 배열이 null이 아닌 길이가 0인지 확인하거나 null 시나리오를 처리하기 위해 검사를 추가로 제공해야합니다.

HQL은 잘 정의 된 (예 : 정적) 쿼리에 더 적합하다고 말합니다. 동적 매개 변수를 해결하면 동적 정렬을 사용하여 작업 할 수 없습니다.

+0

고마워요, 이것은 제가 의심 스럽지만, 여분의 매개 변수를 피하기 위해 표현식을 사용하는 방법이 있기를 바라고 있습니다. – user842800

+0

@ user842800 목록이 없습니다. Hibernate의 질의 처리기는리스트를 지원하기 위해 (즉, 요소 ​​수를 세고 결과 SQL에서 적절한 수의 위치 매개 변수를 생성하기 위해) 뒤에서 어떤 마술을해야한다. 따라서 null을 전달하는 것은 옵션이 아니다. – ChssPly76

+0

SQL 삽입 가능성은 어떨까요? – krzakov

0

당신은 동적으로 쿼리를 생성해야합니다 : 물론

StringBuilder hql = 
    new StringBuilder("SELECT customer FROM Customer as customer INNER JOIN customer.profile as profile where 1 = 1") 
if (statusCodes != null) { 
    hql.append(" and profile.status IN :statusCodes"); 
} 
if (orgIds != null) { 
    hql.append(" and profile.orgId IN :orgIds"); 
} 

, 당신은 또한있을 것이다 나는 두 개의 헬퍼 메소드를 생성 널이 아닌 경우에만 매개 변수를 조회에 설정하십시오.

Map<String, Object> pars = new HashMap<String,Object>(); 
pars.put("statusCodes", statusCodes); 
pars.put("orgIds", orgIds); 

StringBuilder b = "SELECT customer FROM Customer as customer INNER JOIN customer.profile as profile where 1 = 1"; 
if (statusCodes != null) { 
    b.append(" and profile.status in :statusCodes"); 
} 
if (orgIds != null) { 
    b.append(" and profile.orgId in :statusCodes"); 
} 

... 

Query q = session.createQuery(b.toString()); 

... 

for (String p : q.getNamedParameters()) { 
    q.setParameter(p, pars.get(p)); 
} 

일부 개선이 필요 물론 :

+0

감사합니다.하지만 동적 쿼리를 작성하는 것을 피하려고합니다. 일부는 필연적으로 조정하거나 기본 쿼리로 변환해야하기 때문에 .hbm 파일에 쿼리를 저장하고 싶습니다. 따라서 동적으로 구성하는 대신 명명 된 쿼리로 유지 관리하는 방법이 있어야합니다. – user842800

+0

그러면 AFAIK, 가능한 조합 (null-null, notnull-null, null-notnull, notnull-notnull)마다 하나씩 네 가지 쿼리가 필요합니다. 세 번째 매개 변수가 필요하지 않기를 바랄뿐입니다.xml 파일에서 정적 HQL을 SQL로 변경하는 것이 동적 HQL을 Java 파일의 동적 SQL로 변경하는 것보다 훨씬 쉽다는 것을 알 수 있습니다. –

+0

이점은 앱이 명명 된 쿼리가 hql 또는 sql인지 여부를 알 필요가 없다는 사실에서 비롯됩니다. 그것들은 dba 파일로 xml 파일에서 간단히 스왑 될 수 있습니다. 그리고 여러 쿼리를 피하기 위해 OR 조건을 사용하려고합니다. – user842800

5

내 제안은지도에 모든 매개 변수를 넣어 설정 실행하기 전에 맵에서 값을 복용 쿼리에 필요한 모든 매개 변수를 구축 한 후, 동적 쿼리를 구축하는 것입니다 예를 들어 매개 변수가 설정되지 않은 경우 예외를 throw하고 복잡성이 몇 가지 간단한 매개 변수보다 크면 형식화 된 매개 변수를 사용합니다.

+0

SQL 삽입 확률은 어떨까요? – krzakov

+0

이 경우 SQL 주입 기회는 없으며 매개 변수로 처리되므로 이스케이프 처리 된 내용이 있습니다. –

+0

이제 고맙습니다. – krzakov