Hibernate expecting "all", found '(' - what does this mean? - java

I'm getting this error and I can't find any reference to it:
org.hibernate.hql.internal.ast.QuerySyntaxException: expecting "all", found '(' near line 1, column 221 [select new EffectivePermissions(r.id, r.name, r.defaultValue, rc.value AS companyValue, ru.value AS userValue) from permissionsPackage.Entity.Permissions r left join permissionsPackage.Entity.CompanyPermissions rc fetch (r.id=rc.permissionId AND rc.companyId=2313 ) left join permissionsPackage.Entity.UserPermissions ru fetch (r.id=ru.permissionId AND ru.userId=1)]
at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:54)
at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:47)
at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(ErrorCounter.java:79)
Below is the Query I'm using.
this.hql = "select new EffectivePermissions(r.id, r.name, r.defaultValue, rc.value AS companyValue, ru.value AS userValue) "
+ "from "
+ Permissions.class.getName()
+ " r "
+ "left join "
+ CompanyPermissions.class.getName()
+ " rc "
+ "fetch (r.id=rc.permissionId AND rc.companyId="
+ user.getCompany().getId()
+ " ) "
+ "left join "
+ UserPermissions.class.getName()
+ " ru "
+ "fetch (r.id=ru.permissionId AND ru.userId="
+ user.getId()
+ ")";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
permissions = query.list();
I have a class called EffectivePermission with the properties in the constructor and I'd like to get a list based on it.

From the Hibernate Reference chapter 14.3. Associations and joins:
A "fetch" join allows associations or collections of values to be initialized along with their parent objects using a single select ... See Section 19.1, “Fetching strategies” for more information.
You'll also see there that it must be used after the joinkeyword as in from e1 left join fetch e2. It can also be used as in from entity fetch all properties (this is why Hibernate is expecting the all keyword).
Regarding your specific query, and as far as I know, with HQL you can not specify the join conditions. Hibernate will automatically perform the join using the conditions configured in the mapping. This is why it is necessary to have relationships mapped in order to use a HQL join.
And most importantly, remember that joins in HQL are quite different. You don't join two entities, you join an entity with one of its collection-valued properties (associations). Notice you can always do cartesian-like joins (pay attention to performance and always look at the generated queries and execution plans).
As a side note, it can be considered bad practice to append parameter values directly into the query (due to potential injection vulnerabilities). You should be using named parameters instead.

Related

Spring jpa native query sorting adding prefix to order by field name

I have problem with sorting.
Repository method:
#Query(nativeQuery = true,
value = "SELECT D.ID as dealerId , D.NAME as dealerName, K.ID as kpiId, " +
"K.NAME as kpiName FROM REGION R, DEALER D, KPI K "
+ "WHERE R.IMPORTER_ID = :importerId "
+ "AND D.REGION_ID = R.ID "
+ "AND K.IMPORTER_ID = :importerId ")
Page<DealersKpiTargets> getDealersKpiTargets(#Param("importerId") Long importerId, Pageable pageable);
Pageable object:
Page request [number: 0, size 20, sort: name: DESC]
Hibernate log:
Hibernate: SELECT D.ID as dealerId , D.NAME as dealerName, K.ID as kpiId, K.NAME as kpiName FROM REGION R, DEALER D, KPI K WHERE R.IMPORTER_ID = ? AND D.REGION_ID = R.ID AND K.IMPORTER_ID = ? order by R.name desc limit ?
I don't understand where R.name prefix came from, in the order by part in Hibernate (towards the end).
For reference, I am using:
spring-data-jpa version 2.0.7.RELEASE
spring-boot-starter-data-jpa version 2.0.2.RELEASE
UPDATE
I have solved this by changing the query from the native query to jpa query and it's working. And I changed cartesian to join version.
#Query("SELECT dealerEntity.id AS dealerId , dealerEntity.name AS dealerName, kpiEntity.id AS kpiId, " +
"kpiEntity.name AS kpiName FROM KpiEntity kpiEntity "
+ "JOIN RegionEntity regionEntity ON regionEntity.importerEntity = kpiEntity.importerEntity "
+ "JOIN DealerEntity dealerEntity ON dealerEntity.importerEntity = regionEntity.importerEntity "
+ "WHERE kpiEntity.importerEntity = :importerEntity ")
Page<DealersKpiTargets> getDealersKpiTargets(#Param("importerEntity") ImporterEntity importerEntity, Pageable pageable);
here is jira ticket with more details which can be key for resolution (https://jira.spring.io/browse/DATAJPA-1613).
QueryUtils.ALIAS_MATCH
(?<=from)(?:\s)+([._[\P\\{Z}&&\P\\{Cc}&&\P\\{Cf}&&\P\\{P}]]+)(?:\sas)*(?:\s)+(?!(?:where|group\s*by|order\s*by))(\w+)
responsible to incorrect alias extraction. The solution for my case was rewrite native query, so it doesn't match the provided regexp.
This may be a little late to answer this question. But thought to share how I got around this issue.
For native queries, it seems like hibernate tries to use the alias of the first table used in the query when it applies the sorting criteria. In your case, the first table alias is R hence you see R.name desc in the query generated by hibernate.
One way to get around this issue is to wrap your query in a select clause and name it as R, like
"SELECT * FROM(SELECT D.ID as dealerId , D.NAME as dealerName, K.ID as kpiId, " +
"K.NAME as kpiName FROM REGION R, DEALER D, KPI K "
+ "WHERE R.IMPORTER_ID = :importerId "
+ "AND D.REGION_ID = R.ID "
+ "AND K.IMPORTER_ID = :importerId ) R"
This way at runtime hibernate would apply the sort criteria on top of your query which corresponds to R now.
It has Sort class for this you can use this maybe. Besides, it is easy to use.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.sorting
I faced similar issue especially in case of complex queries where there is ORDER BY with in the query. I was getting syntax error because a , was getting added before ORDER BY.
The way I solved this issue was to create a VIEW with the SELECT query having necessary fields required for result set and WHERE condition (so you can run query with params in WHERE condition against the VIEW). And write native query to SELECT FROM the VIEW
CREATE VIEW my_view AS (// your complex select query with required fields);
#Query("SELECT field1 AS alias1, field2 AS alias2 FROM my_view "
+ "WHERE field3 = :param1 AND field4 = :param2")
Page<MyDto> myFunction(#Param("param1") Long param1, #Param("param1") String param2, Pageable pageable);

Hibernate: MySQL error unknown column in having clause although column exists

I have a JPQL query in a repository that is the equivalent of the MySQL query below:
SELECT DISTINCT ji.* FROM tracker_job_item AS ji
JOIN tracker_work AS w ON ji.id=w.tracker_job_item_id
JOIN tracker_work_quantity AS wq on w.id=wq.tracker_work_id
WHERE w.work_type = 'CUTTING' AND ji.is_finished=0
GROUP BY wq.tracker_work_id
HAVING ji.quantity != SUM(wq.received_quantity)
The MySQL version works just fine, but the JPQL equivalent gives an exception: Unknown column 'jobitem0_.quantity' in 'having clause'
The JPQL query is like below:
#Query("select distinct ji from JobItem ji" +
" join Work w on ji.id=w.jobItem.id" +
" join WorkQuantity wq on w.id=wq.work.id" +
" where w.workType='CUTTING' and ji.isFinished=false and ji.jobItemName like %:search%" +
" group by ji.id" +
" having ji.quantity != sum(wq.receivedQuantity)")
Page<JobItem> findAllActiveCuttingJobs(Pageable pageable, #Param("search") String search);
Please help me with why I'm getting the error even though the field quantity exists in JobItem.
You can't reference a column in the having clause that isn't in the group by clause, definitely in JPA and (normally at least) in SQL. Looks like MySQL is letting you get away with it but JPA isn't.
See here:
http://learningviacode.blogspot.co.uk/2012/12/group-by-and-having-clauses-in-hql.html

Why hibernate generates ~500 SQL queries?

When trying to optimize MySQ slow queries generated by Hibernate 4.2 in a legacy project, I found out that the code below generates nearly 500 SQL queries (with many duplicates) :
class MyDAO {
public List<Message> findMessages() {
Session session = MyHibernateUtils.openSession();
String queryStr = "SELECT DISTINCT m FROM Message m "
+ " LEFT JOIN fetch m.types types "
+ " LEFT JOIN fetch m.mainType mainType "
+ " LEFT JOIN fetch m.place place "
+ " LEFT JOIN fetch m.building building "
+ " LEFT JOIN fetch m.city city "
+ " LEFT JOIN fetch m.kind kind "
+ " LEFT JOIN fetch m.domain domain "
+ " LEFT JOIN fetch m.action action "
+ " LEFT JOIN fetch m.customParameterA customParameterA "
+ " LEFT JOIN fetch m.customParameterB customParameterB "
+ " LEFT JOIN fetch m.scheduleEvents scheduleEvents "
+ " LEFT JOIN fetch m.comments comments "
+ " LEFT JOIN fetch m.messageLastActivities messageLastActivities "
+ " LEFT JOIN fetch m.customListA customListA "
+ " LEFT JOIN fetch m.childEvents childEvents "
+ " LEFT JOIN fetch m.parentEvent parentEvent "
+ " WHERE ...";
List<Message> messages;
try {
session.getTransaction().begin();
Query query = session.createQuery(queryStr);
query.setTimeout(10);
messages = query.list();
session.getTransaction().commit();
} catch (RuntimeException e) {
session.getTransaction().rollback();
throw e;
} finally {
session.close();
}
return messages;
}
}
How can I avoid having so many SQL queries ?
I don't know if it helps but there are many onyToMany and manyToMany relationships between the entities.
Thank for your help.
You should check the queries hibernate is generating, to see which table is accessed frequently.
You have to join fetch entities related by your related entities as well, See here:
Hibernate is doing multiple select requests instead one (using join fetch)
I personally prefer lazy loading with an annotated #BatchSize() to keep the lazy-query-count small. Just using a Batch-Size of 2 will cut your query count in half then.
Also have a look at the #Cache Annotation which can reduce your query count in a significant way. (Just thinking of all the almost static stuff like city/building/type/domain and the like)
Depending on your relationship design, default value of Fetch in #OneToMany and #ManyToMany is LAZY, that means for loading related record in child entity (when you call getter method) hibernate executes one more query to load that record (for example: select * from foo where id = ?) , so if loaded entity (main entity) contains many child entities such as ManyToMany or OneToMany you will see many queries in console.
To void these queries, you can set Fetch to EAGER but this is not recommended on optimization.
#Entity
public class MainEntity {
#ManyToMany(Fetch = FetchType.EAGER)
public List<Foo> foos;
}

Group by in HQL and Hibernate Criteria queries (ORA-00979: not a GROUP BY expression)

I am new to new to hibernate and Java, so I apologize if these are ridiculously simply questions.
I don't understand why the following query gives me the error "ORA-00979: not a GROUP BY expression".
Query q = session.createQuery (
"select new tdata.Summary(tbForm.rYear, SUM(tbForm.pWaste)) "
+ "from TrForm tbForm "
+ "left join fetch tbForm.indKey "
+ "where tbForm.indKey.grpCode='999' "
+ "group by tbForm.rYear " );
The possible reasons for this error do not seem to apply to my query because I am including group by function SUM, and I do not have any expressions in the select that are not in the group by.
I also tried to write a criteria query to do what I need, and I could not get that to work either. In the criteria version, I am confused as to how to add restrictions to fetched data and how to get the data into the Summary object.
Criteria criteria = session.createCriteria(TrForm.class)
.setFetchMode("DimInd",FetchMode.JOIN)
.add(Restrictions.eq("indKey.indCode", "999"))
.setProjection(Projections.projectionList()
.add(Projections.groupProperty("rYear"))
.add(Projections.sum("pWaste")));
summaryList = (List<Summary>) criteria.list();
Any help would be greatly appreciated.
Thanks!
Update:
Thank you so much! I removed the "left join fetch tbForm.indKey" and the HQL version worked!
Generalized query is
select R_YEAR, sum(P_WASTE)
from TR_FORM tbForm
left join DIM_IND ind
on tbForm.IND_KEY = ind.IND_KEY
where ind.GRP_CODE='999'
group by tbForm.R_YEAR
tdata is the folder in which I have the java code for the data models.

How to join two unrelated entities using JPA and Hibernate

I have two tables - one containing Address and another containing Photographs. The only common field between them is the PersonID. These were mapped to two POJO Classes Address and Photo. I was able to fetch details in these tables by creating criteria and adding restrictions on the fields . How should we write a join on the two tables. Is it possible to get the result as two objects -Address and Photo.
I want to do a left join so that i can get records of persons without photos as well.
I have read that this is possible only using hql but Can this be done using criterias as well?
You can easily write HQL query that will return result as two objects using Theta Join (as Adrian noted). Here is an example:
String queryText = "select address, photo from Address address, Photo photo "
+ " where address.personID=photo.personId";
List<Object[]> rows = session.createQuery(queryText).list();
for (Object[] row: rows) {
System.out.println(" ------- ");
System.out.println("Address object: " + row[0]);
System.out.println("Photo object: " + row[1]);
}
As you can see query returns list of Object[] arrays that represents each fetched row. First element of this array will contain one obejct and second element - another.
EDIT:
In case of left join I think you need to use native SQL query (not HQL query). Here how you can do this:
String queryText = "select address.*, photo.* from ADDRESS address
left join PHOTO photo on (address.person_id=photo.person_id)";
List<Object[]> rows = sess.createSQLQuery(queryText)
.addEntity("address", Address.class)
.addEntity("photo", Photo.class)
.list();
This should work for your case.
Basically, you have two options:
Since Hibernate 5.1, you can use ad-hoc joins for unrelated entities.
Tuple postViewCount = entityManager.createQuery(
"select p as post, count(pv) as page_views " +
"from Post p " +
"left join PageView pv on p.slug = pv.slug " +
"where p.title = :title " +
"group by p", Tuple.class)
.setParameter("title", "High-Performance Java Persistence")
.getSingleResult();
Prior to Hibernate 5.1, you could only use theta-style joins. However, a theta-style join is equivalent to an equijoin, hence you can only emulate INNER JOINs not OUTER JOINs.
List<Tuple> postViewCount = entityManager.createQuery(
"select p as post, count(pv) as page_views " +
"from Post p, PageView pv " +
"where p.title = :title and " +
" ( p.slug = pv.slug ) " +
"group by p", Tuple.class)
.setParameter("title", "Presentations")
.getResultList();
Finally after 12 years the Hibernate team has implemented such a feature
From Hibernate docs:
The FROM clause can also contain explicit relationship joins using the join keyword. These joins can be either inner or left outer style joins.
List<Person> persons = entityManager.createQuery(
"select distinct pr " +
"from Person pr " +
"join pr.phones ph " +
"where ph.type = :phoneType", Person.class )
.setParameter( "phoneType", PhoneType.MOBILE )
.getResultList();
List<Person> persons = entityManager.createQuery(
"select distinct pr " +
"from Person pr " +
"left join pr.phones ph " +
"where ph is null " +
" or ph.type = :phoneType", Person.class )
.setParameter( "phoneType", PhoneType.LAND_LINE )
.getResultList();
Or you can use WITH and ON keywords. A remark on those
The important distinction is that in the generated SQL the conditions
of the WITH/ON clause are made part of the ON clause in the generated
SQL, as opposed to the other queries in this section where the
HQL/JPQL conditions are made part of the WHERE clause in the generated
SQL.
Example
List<Object[]> personsAndPhones = session.createQuery(
"select pr.name, ph.number " +
"from Person pr " +
"left join pr.phones ph with ph.type = :phoneType " )
.setParameter( "phoneType", PhoneType.LAND_LINE )
.list();
I am currently eager to try the new feature.
Joining two unrelated entities are possible in Hibernate 5.1.
Eg :
select objA from ObjectA objA
JOIN ObjectB objB on objB.variable = objA.variable
where objA.id = 1
It's best to have a class containing those classes you want to join to have them all together.
But if you are joining these tables just for some occasional purposes, you can use criteria and manually load data from each table and put them together. (and yes, you can have these tables' data separately if for Address and Photo there are two separate classes and tables)
What you are looking for is
HQL
Join on fields that you haven't modeled as relationships
Left Join
(During the time the question was first asked and this answer was given) Hibernate supports Theta Join which allows you to do 1 & 2. However, only inner join is available for theta join style.
Personally I would recommend you to model proper relationships, so you just need 1 & 3 which is well-supported in HQL.
(Another answer actually provided an update on new Hibernate feature that provides such feature, that you may simply refer to)

Categories