2012-01-13 10 views
5

지금까지 성공하지 못했지만 SQL 쿼리를 Criteria API로 변환하려고합니다. 필요한 값을 반환하는 두 개의 개별 쿼리를 만들 수 있지만 단일 쿼리에서 이들을 결합하는 방법을 모르겠습니다.JPA 2 + Criteria API - 하위 쿼리 정의

: 나는 작은 래퍼/헬퍼 클래스를 정의 된 응용 프로그램에서

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<intCompany> qTicket = cb.createQuery(intCompany.class); 
Root<Ticket> from = qTicket.from(Ticket.class); 
Path groupBy = from.get("company");   
Predicate state = cb.notEqual(from.<State>get("state"), getStateById(16));   
qTicket.select(cb.construct(
    intCompany.class, cb.count(from),from.<Company>get("company"))) 
     .where(state).groupBy(groupBy);     
em.createQuery(qTicket).getResultList(); 

:

select company.*, ticketcount.counter from company 
    join 
(select company, COUNT(*) as counter from ticket where state<16 group by company) ticketcount 
on company.compid = ticketcount.company; 

이 기준 쿼리는 내부 쿼리 결과를 반환 여기

가 작동하는 SQL 문이다
public class intCompany{ 
    public Company comp; 
    public Long opentickets; 
    public intCompany(Long opentickets,Company comp){ 
     this.comp = comp; 
     this.opentickets = opentickets; 
    } 
    public intCompany(){ 

    } 
} 

누구나 어떻게 작동하는지 알 수 있습니까?

업데이트 감사합니다. 내가 제안한 기준 쿼리를 변경했습니다. 마지막으로 원하는 정보를 얻으려면 루프를 추가해야했습니다.

List<intCompany> result = em.createQuery(cq).getResultList(); 
List<Company> cresult = new ArrayList(); 
    for(intCompany ic: result){ 
     ic.comp.setOpentickets(ic.opentickets.intValue()); 
     cresult.add(ic.comp); 
    } 
return cresult; 

아마도 원래 SQL을 Criteria API로 변환 할 수 없을 수도 있습니다.

내가 그렇지 않으면 내가 티켓 테이블에 항목이없는 회사를하지 않는

select company.*, ticketcount.counter from company 
    left join 
(select company, COUNT(*) as counter from ticket where state<16 group by company) ticketcount 
on company.compid = ticketcount.company; 

원래 SQL 식을 변경했다 알아 냈

또 다른 갱신.

다른 제안 사항이 있습니까?

답변

2

거의 모든 작업을 완료했습니다.

//---// 
CriteriaBuilder cb = em.getCriteriaBuilder(); 
//Your Wrapper class constructor must match with multiselect arguments 
CriteriaQuery<IntCompany> cq = cb.createQuery(IntCompany.class); 
//Main table 
final Root<Ticket> fromTicket= cq.from(Ticket.class); 
//Join defined in Ticket Entity 
final Path company = fromTicket.get("company"); 
//Data to select 
cq.multiselect(cb.count(from), company); 
//Grouping 
cq.groupBy(company); 
//Restrictions (I don't really understand what you're querying) 
Predicate p = cb.lessThan(fromTicket.get("state"), 16); 
//You can add more restrictions 
// p = cb.and/or(p, ...); 
cq.where(p); 
List<IntCompany> results = entityManager.createQuery(cq).getResultList(); 

예상대로 작동합니다.

2

비슷한 문제가있었습니다. 내 솔루션 왼쪽 된 외부 조인을 사용했습니다.

CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
CriteriaQuery<Entity> query = cb.createQuery(Entity.class); 
Root<Entity> root = query.from(Entity.class); 

Join<Entity,ChildEntity> join = root.join(Entity_.children, JoinType.LEFT); 
query.groupBy(root.get(Entity_.id)); 
query.select(
    cb.construct(
    EntityDTO.class, 
    root.get(Entity_.id), 
    root.get(Entity_.name), 
    cb.count(join) 
)); 

가 자식 엔티티 (티켓)이없는 경우에도 엔티티 기록 (회사)를 얻을 것이다이 JoinType.LEFT 보장한다.

Entity 클래스 :

@Entity 
public class Entity { 
    ... 

    @OneToMany(targetEntity = ChildEntity.class, mappedBy = "parent", fetch = FetchType.LAZY, orphanRemoval = false) 
    private Set<ChildEntity> objects; 

    ... 
} 

정적 모델 :

@StaticMetamodel(Entity.class) 
public class Entity_ { 
    public static volatile SingularAttribute<Entity, Long> id; 
    public static volatile SingularAttribute<Entity, String> name; 
    ... 
    public static volatile SetAttribute<Entity, ChildEntity> objects; 
}