Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA 2 + Criteria API - Defining a subquery

I try to convert a sql query to Criteria API without success so far. I can create two separate queries which return the values I need, but I don't know how to combine them in a single query.

Here is the sql statement which works:

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;

This Criteria query returns the inner query results:

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

In the application I defined a small wrapper/helper class:

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

    }
}

So does anyone has an idea how to get this working?

Update

Thank you. I changed my criteria query as you suggested. I just had to add a loop at the end to get the information I wanted.

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;

Maybe it is just not possible to convert the original sql to Criteria API.

Another update

I figured out I had to change the original sql expression to

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;

Otherwise I do not get companies with no entries in the ticket table.

So are there any other suggestions?

like image 206
Thaddel Avatar asked Oct 10 '22 00:10

Thaddel


1 Answers

You have almost everything done.

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

This should work as expected.

like image 141
Marc Nuri Avatar answered Oct 13 '22 12:10

Marc Nuri