Tuple result Criteria API subquery
Asked Answered
S

2

8

I am trying to use subqueries in an application I am writing using JPA 2.0 type-safe criteria API, with Hibernate 3.6.1.Final as my provider. I have no problem selecting primitive types (Long, MyEntity, etc.), but I want to select multiple columns.

Here's an example of something completely reasonable. Ignore the needless use of subquery -- it is simply meant as illustrative.

    EntityManager em = getEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Tuple> cq = cb.createTupleQuery();

    Subquery<Tuple> subQ = cq.subquery(Tuple.class);
    Expression<Long> subqCount;
    {
        Root<MyEntity> root = subQ.from(MyEntity.class);
        Path<MyEntity> filter = root.get(MyEntity.challenge);

        subqCount = cb.count(root);

        // How to select tuple?
        Selection<Tuple> tuple = cb.tuple(filter, subqCount);

                    // !! Run-time exception here
        Expression<Tuple> tupleExpr = (Expression<Tuple>) tuple; 

        // Not sure why I can't use multiSelect on a subQuery
        // #select only accepts Expression<Tuple>
        createSubQ.select(tupleExpr);

        createSubQ.groupBy(filter);
    }

    cq.multiselect(subqCount);

Although the compiler doesn't complain, I still get a run-time exception.

    java.lang.ClassCastException: org.hibernate.ejb.criteria.expression.CompoundSelectionImpl cannot be cast to javax.persistence.criteria.Expression
  • Is this a bug in hibernate, or am I doing something wrong?
  • If you can't use multiselect on a subquery, then how can you perform a groupBy?
  • If you can't use groupBy on a subquery, why is it in the API?
Siusiubhan answered 15/3, 2011 at 20:27 Comment(1)
I still have not found an answer to this question, and I think it is stil valid.Siusiubhan
O
5

I have the same problem.

I can only attempt to answer your last question by saying you can only really use sub queries to perform very simple queries like:

SELECT name FROM Pets WHERE Pets.ownerID in (
    SELECT ID FROM owners WHERE owners.Country = "SOUTH AFRICA"
)

The other thing I wanted to say was how much this incident reminds me of xkcd #979.

Outleap answered 29/11, 2011 at 9:7 Comment(2)
+1 - Love the XKCD reference, and I agree that it seems like subqueries are rather limited. Have you tried doing group-by subqueries using JPAQL?Siusiubhan
I haven't, the example I was working on (I am still quite new to JPA) needed the query's structure to change quite a lot based on what was selected so I basically just used the subquery I needed as my main query and then filtered out everything else "manually". The query would only ever return less than a few thousand tuples anyway so it is not too slow.Outleap
D
0

I had similar problem. I had specification, and I wanted to get ids of objects matching this specification.

My solution:

    CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
    CriteriaQuery<Tuple> tupleCriteriaQuery = criteriaBuilder.createTupleQuery();

    Root<Issue> root = tupleCriteriaQuery.from(Issue.class);
    tupleCriteriaQuery = tupleCriteriaQuery.multiselect(root.get(IssueTable.COLUMN_ID));//select did not work.
    tupleCriteriaQuery = tupleCriteriaQuery.where(issueFilter.toPredicate(root, tupleCriteriaQuery, criteriaBuilder));

    List<Tuple> tupleResult = em.createQuery(tupleCriteriaQuery).getResultList();

First I select columns (In my case I need only one column), and then I call where method to merge with my given specification.

Deese answered 4/5, 2016 at 9:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.