How to resolve Oracle's 'rownum' pseudocolumn with JPA Criteria API? - java

I would like to get first row from database using JPA Criteria. I use JPA, Hibernate 4.2.7.
In SQL, statement looks like:
SELECT * FROM houses WHERE rownum = 1;
My Java code to achive that looks like:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<House> query = builder.createQuery(House.class);
Root<House> root = query.from(House.class);
query.select(root).where(builder.equal(root.get("rownum"), 1));
TypedQuery<House> tQuery = entityManager.createQuery(query);
House house = tQuery.getSingleResult();
But 'rownum' pseudocolumn cannot be resolved, I get exception:
java.lang.IllegalArgumentException: Unable to resolve attribute [rownum] against path
at org.hibernate.ejb.criteria.path.AbstractPathImpl.unknownAttribute(AbstractPathImpl.java:120)
at org.hibernate.ejb.criteria.path.AbstractPathImpl.locateAttribute(AbstractPathImpl.java:229)
at org.hibernate.ejb.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:200)
Is is possible, and if so, how to get 'rownum' pseudocolumn with Criteria API? Thanks for any suggestions.

You can accomplish this using setFirstResult and setMaxResults.
session.createCriteria(Foo.class)
.setFirstResult(0)
.setMaxResults(1);

you can set rownum or limits in property of query;
Query q =entityManager.createQuery("select * from employee_table");
q.setFirstResult(0);
q.setMaxResults(30);

Related

QueryDSL subquery not working

I'm trying to recreate the following SQL query in QueryDSL. The following is my SQL query which is currently working as inteded.
SELECT * FROM room x WHERE unit_id = (SELECT unit_id FROM room WHERE unit_id = x.unit_id GROUP BY unit_id HAVING(SUM(sqft) > 0))
I'm trying to write a QueryDSL query that does the same thing but honestly can't come any further than the bottom query.
JPASubQuery subQuery = new JPASubQuery();
subQuery.from(qRoom).groupBy(qRoom.unit).having(qRoom.sqft.sum().goe(0));
JPAQuery unitquery = from(qRoom)
.where(qRoom.building.eq(building)).where(qRoom.unit.eq(subQuery));
return unitquery.list(qRoom);
The above query isn't working and i'm having trouble using subqueries in QueryDSL. What should I add/change to make this query working?
Fixed it.
I just needed to change .where(qRoom.unit.eq(subQuery)); too .where(qRoom.unit.in(subQuery.list(qRuimte.unit)));

JPA CriteriaQuery with LEAST and GREATEST functions

I am have a problem where i need to join two tables using the LEAST and GREATEST functions, but using JPA CriteriaQuery. Here is the SQL that i am trying to duplicate...
select * from TABLE_A a
inner join TABLE_X x on
(
a.COL_1 = least(x.COL_Y, x.COL_Z)
and
a.COL_2 = greatest(x.COL_Y, x.COL_Z)
);
I have looked at CriteriaBuilder.least(..) and greatest(..), but am having a difficult time trying to understand how to create the Expression<T> to pass to either function.
The simplest way to compare two columns and get the least/greatest value is to use the CASE statement.
In JPQL, the query would look like
select a from EntityA a join a.entityXList x
where a.numValueA=CASE WHEN x.numValueY <= x.numValueZ THEN x.numValueY ELSE x.numValueZ END
and a.numValueB=CASE WHEN x.numValueY >= x.numValueZ THEN x.numValueY ELSE x.numValueZ END
You can code the equivalent using CriteriaBuilder.selectCase() but I've never been a big fan of CriteriaBuilder. If requirements forces you to use CriteriaBuilder then please let me know and I can try to code the equivalent.
CriteriaBuilder least/greatest is meant to get the min/max value of all the entries in one column. Let's say you want to get the Entity that had the alphabetically greatest String name. The code would look like
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery(EntityX.class);
Root<EntityX> root = query.from(EntityX.class);
Subquery<String> maxSubQuery = query.subquery(String.class);
Root<EntityX> fromEntityX = maxSubQuery.from(EntityX.class);
maxSubQuery.select(cb.greatest(fromEntityX.get(EntityX_.nameX)));
query.where(cb.equal(root.get(EntityX_.nameX), maxSubQuery));
I created a sample Spring Data JPA app that demonstrates these JPA examples at
https://github.com/juttayaya/stackoverflow/tree/master/JpaQueryTest
It turns out that CriteriaBuilder does support calling LEAST and GREATEST as non-aggregate functions, and can be accessed by using the CriteriaBuilder.function(..), as shown here:
Predicate greatestPred = cb.equal(pathA.get(TableA_.col2),
cb.function("greatest", String.class,
pathX.get(TableX_.colY), pathX.get(TableX_.colZ)));

Executing hibernate template's findByNamedQuery

I'm pretty new to hibernate and I was trying it out in one of my applications. I chose to use annotation session factory bean and my editor generated entity classes for each table from the DB which had named queries. hibernateTemplate.findByAll worked fine. But when I tried hibernateTemplate.findByNamedQuery("findById", "<some_id>"), it gave an error: java.lang.IndexOutOfBoundsException: Remember that ordinal parameters are 1-based. After a bit of googling, tried out multiple solutions:
Changed the namedQuery that was generated by editor from : #NamedQuery(name = "Table.findById", query = "SELECT u FROM Table t WHERE t.id = :id"), to : #NamedQuery(name = "Table.findById", query = "SELECT u FROM Table t WHERE t.id = ?") but got the same error.
Tried using hibernateTemplate.findByNamedParam but ended up getting error: java.lang.IllegalArgumentException: node to traverse cannot be null!
I can use hibernateTemplate.find() to achieve this but how do I use findByNamedQuery/Param methods to achieve the same since the documentation says these methods may be used to fetch records based on a field?

Getting error in joining tables using hibernate

I am trying to join multiple table using hibernate but its not working for me can someone please help me out.
I tried Criteria that was not working then thought of using query even that is not working
My code looks like
final Session session = getSession();
String query = "SELECT r.REFERRER_ID from REFERRAL_PAYMENT_INFO r, SIGNUP_REFERRAL s";
Query q = session.createQuery(query);
List list = q.list();
I am getting this error -
"Caused by: org.hibernate.hql.ast.QuerySyntaxException:
REFERRAL_PAYMENT_INFO is not mapped [SELECT r.REFERRER_ID from REFERRAL_PAYMENT_INFO
r, SIGNUP_REFERRAL s]"
You must use the classes (entities) you mapped in HQL queries. If you want to use normal SQL, then you have to call session.createSQLQuery().
Look at the documentation for hibernate session:
http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html

Need help creating JPA criteria query

I'm building my first Java EE web application using Glassfish and JSF. I'm fairly new to the criteria query and I have a query I need to perform but the javaee6 tutorial seems a little thin on examples. Anyway, I'm having a hard time creating the query.
Goal: I want to pull the company with the most documents stored.
Companies have a OneToMany relationship with Documents.
Documents has a ManyToOne relationship with several tables, the "usertype" column distinguishes them.
MySQL query:
SELECT USERID, COUNT(USERID) AS CNT
FROM DOCUMENTS
WHERE USERTYPE="COMPANY"
GROUP BY USERID
ORDER BY CNT DESC
Thanks
--update--
Based on user feedback, here is what I have so far:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Documents> cqry = cb.createQuery(Documents.class);
//Intersting Stuff
Root<Documents> root = cqry.from(Documents.class);
Expression userid = root.get("userID");
Expression usertype = root.get("userType");
Expression count = cb.count(userid);
cqry.multiselect(userid, count);
Predicate userType = cb.equal(usertype, "COMPANY");
cqry.where(userType);
cqry.groupBy(userid);
cqry.orderBy(cb.desc(count));
//more boilerplate
Query qry = em.createQuery(cqry);
List<Documents> results = qry.getResultList();
The error I get is:
Exception Description: Partial object queries are not allowed to maintain the cache or be edited. You must use dontMaintainCache().
Typical error, means nothing to me!
Your query doesn't return a complete entity object as you're only selecting two fields of the given table (this is why you're getting an error that says yadayadapartialyadayada).
Your solution is almost right, here's what you need to change to make it work—making it partial.
Instead of a plain CriteriaQuery<...> you have to create a tuple CriteriaQuery<..> by calling CriteriaBuilder.createTupleQuery(). (Basically, you can call CriteriaBuilder.createQuery(...) and pass Tuple.class to it as an argument. Tuple is a sort of wildcard entity class.)
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq= cb.createTupleQuery();
Root<Documents> root = cq.from(Documents.class);
Expression<Integer> userId = root.get("USERID");
Expression<String> userType = root.get("USERTYPE");
Expression<Long> count = cb.count(userId);
cq.multiselect(userId.alias("USERID"), count.alias("CNT"));
cq.where(cb.equal(userType, "COMPANY");
cq.groupBy(userId);
cq.orderBy(cb.desc(count));
TypedQuery<Tuple> tq = em.createQuery(cq);
for (Tuple t : tq.getResultsList()) {
System.out.println(t.get("USERID"));
System.out.println(t.get("CNT"));
}
(Accessing fields of a Tuple gave me an error if I didn't use aliases for them (in multiselect(...)). This is why I've used aliases, but this can be tackled more cleanly by using JPA 2's Metamodel API, which is described in the specification quite thoroughly. )
The documentation for CriteriaQuery.multiselect(...) describes the behaviour of queries using Tuple objects more deeply.
If you are using Hibernate, this should work:
ProjectionList pl = Projections.projectionList()
.add(Projections.groupProperty("userid"))
.add(Projections.property("userid"))
.add(Projections.count("userid"));
Criteria criteria = session.createCriteria(Document.class)
.add(Restrictions.eq("usertype",usertype))
.setProjection(pl)
.addOrder(Order.desc("cnt"));
Hope it helps!
Take a look into this easy tutorial. It uses JPA2 and Criteria
http://www.jumpingbean.co.za/blogs/jpa2-criteria-api
Regards!
You need to add a constructor to Documents with only userid and count because you will need it on:
cqry.multiselect(userid, count);

Categories