2012-01-13 16 views
5

Cerco di convertire una query sql in API Criteria senza esito positivo finora. Posso creare due query separate che restituiscono i valori che mi servono, ma non so come combinarli in una singola query.API Criteri JPA 2 + - Definizione di una sottoquery

Ecco la dichiarazione di sql che funziona:

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; 

Questa query criteri restituisce i risultati della query interne:

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(); 

Nell'applicazione ho definito una piccola classe wrapper/helper:

public class intCompany{ 
    public Company comp; 
    public Long opentickets; 
    public intCompany(Long opentickets,Company comp){ 
     this.comp = comp; 
     this.opentickets = opentickets; 
    } 
    public intCompany(){ 

    } 
} 

Così qualcuno ha un'idea di come farlo funzionare?

Aggiornamento

Grazie. Ho modificato la mia query sui criteri come suggerito. Ho solo dovuto aggiungere un loop alla fine per ottenere le informazioni che volevo.

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; 

forse è solo non è possibile convertire lo SQL originale per Criteri API.

Un altro aggiornamento

ho capito che dovevo cambiare l'espressione SQL originale per

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; 

Altrimenti non ottengo le aziende senza voci nella tabella biglietto.

Quindi ci sono altri suggerimenti?

risposta

2

Hai quasi fatto tutto.

//---// 
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(); 

Questo dovrebbe funzionare come previsto.

2

Ho avuto un problema simile. La mia soluzione era usare i join esterni a sinistra.

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) 
)); 

Questo JoinType.LEFT garantisce che si ottengono record di entità (società), anche se non ha entità figlio (biglietti). Classe

Entity:

@Entity 
public class Entity { 
    ... 

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

    ... 
} 

modello statico:

@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; 
} 
Problemi correlati