Using sub queries in Hibernate - java

Consider a sample query which uses two tables. Query would be like:
select t1.name, t1.address, (select count(*) from table2 t2 where t1.userid = t2.userid) as totalpoints from table1 t1
There are two bean classes named Table1.java and Table2.java. My DAO class extends HibernateDAOSupport. Is it possible to use this query with the two bean class in getHibernateTemplate.find() function call?
Any help would be appreciable.
Thanks.

Yes, it's possible. The HQL query will be nearly identical to the SQL query. Note that your SQL is invalid, though. There is even an example of such a query in the Hibernate documentation about subqueries.

Related

Java Persistence Entitymanager - Select from another query's result set

I currently have the query stated below. I know this works as a SQL query, but because I am using the EntityManager, from javax.persistence, it requires JPQL. And I don't know JPQL. If there is a way to rewrite this in JPQL that would be nice.
Query q = entityManager.createNativeQuery("
WITH original AS (SELECT *, COUNT(ref) as c FROM Tri WHERE triH IN :list GROUP BY ref
SELECT ref FROM original WHERE c = :amtTri");
q.setParameter("list", posTri);
q.setParameter("amtTri", posTri.size());
Actual query:
WITH original AS (SELECT *, COUNT(ref) as c FROM Tri WHERE triH IN :list GROUP BY ref
SELECT ref FROM original WHERE c = :amtTri
I am trying to do this in a Quarkus project using the Repository method, if there is a way to use that, that would also be fine
Thanks in advance!
I believe that using the EntityManager don't obligates you to use JPQL, you can also use Native Queries.
As your query looks not so simple (for me at least), I would do it using Native Queries and not JPQL. You can run Native Queries using the EntityManager from javax.persistence. This tutorial explains how you can do this.

Hibernate - Select all rows in a table

Im trying to get my query to load all rows in a table, im working with hibernate.
#Override
public List<Teacher> getTeachersBySubject(Subject subject) {
List<Teacher> teachersBySubject = entityManager.createQuery("SELECT * FROM teacher t INNER JOIN teacher_subject ts on t.email = ts.email")
.getResultList();
return teachersBySubject;
}
The * (All) Gives the error im dealing with, it won't load because of hibernate
the error that im getting is this : org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: * near line 1, column 8 [SELECT * FROM com.scalda.vos.models.Teacher t INNER JOIN teacher_subject ts on t.email = ts.email]
its not native and your writing hql so replace * with t.
You have written a native query, which must be compiled using the createNativeQuery method.
The createQuery expects HQL and not native SQL, and therefore to do it in HQL use just "teacher FROM Teacher". Also, if you are just retrieving a Teacher and not a Teacher-Subject hybrid then, Hibernate can also help you with retrieving associations check this
HIbernate expects you to use JPQL, it looks like SQL, but should be like this:
SELECT t FROM teacher t JOIN t.subject
Of course, it depends on how you Teacher class is annotated (ManyToMany, OneToMany mappings).
as my recommendation, use hql for clear code in hibernate or using criteria
but, still running well in native.
For native SQL, use createSqlQuery, like :
List<Teacher> teachersBySubject = entityManager.createSqlQuery("SELECT * FROM teacher t INNER JOIN teacher_subject ts on t.email = ts.email")
.getResultList();

How to use 'Insert' in a nativeSQL query in Hibernate outside the mapped class ?

In Hibernate, you can use the 'SELECT' queries in native SQL like this :
Query query = session.createSQLQuery("SELECT ... FROM ...");
But I would want to use an 'INSERT' query.
So, I looked at the documentation, and it seems you must go directly to the mapped class and write the code inside it.
But I would want to use it as I do for a 'SELECT' query (outside the mapped class) since it looks much more pratical.
Indeed, why would the treatment be different between 'SELECT' and 'INSERT' for a hibernate native SQL query ?
An HQL INSERT cannot be used to directly insert arbitrary entities—it can only be used to insert entities constructed from information obtained from SELECT queries (unlike ordinary SQL, in which an INSERT command can be used to insert arbitrary data into a table, as well as insert values selected from other tables).
Here’s the syntax of the INSERT statement:
INSERT INTO path ( property [, ...]) select
The name of an entity is path. The property names are the names of properties of entities listed in the FROM path of the incorporated SELECT query. The select query is an HQL SELECT query (as described in the next section).
As this HQL statement can only use data provided by an HQL select, its application can be limited. An example of copying users to a purged table before actually purging them might look like this:
Query query=session.createQuery("insert into purged_accounts(id, code, status) "+
"select id, code, status from acount where status=:status");
query.setString("status", "purged");
int rowsCopied=query.executeUpdate();
Or you can use
session.persist(obj);
where obj is the object of the POJO class let say TestClass
TestClass obj=new TestClass('','',''); //paramatrized constructor for the values you want to insert in your database.

Left join on unrelated tables in Query DSL and JPA

I have two unrelated tables, each one with field email. I need a query which introduces column taken from second table if emails match or will be null if no match is found. In SQL this is easy:
SELECT tableA.id, tableA.email, tableB.name
FROM tableA
LEFT JOIN tableB ON tableA.email=tableB.email
ORDER BY tableB.name
Unfortunately JPA doesn't allow joins over unrelated entities so I converted it to:
SELECT tableA.id, tableA.email,
(SELECT tableB.name FROM tableB WHERE tableB.email=tableA.email) AS aname
FROM tableA
ORDER BY aname
Now, it works as JPA query but we are using Query DSL so off we go to converting it:
JPQLQuery query = new JPAQuery(em);
List<Dto> items=query.from(qTableA)
.list(new QDto(qTableA.id, qTableA.email,
new JPASubQuery().from(qTableB)
.where(qTableB.email.eq(qTableA.email)).unique(qTableB.name)))
It works but now I have no idea how to implement sorting and filtering by field introduced by subquery.
Dto is a POJO used to collect results, QDto is a class autogenerated from Dto.
Question is: how to join two unrelated tables using Query DSL and JPA and avoiding native SQL? Is it possible? Sorting and filtering on fields from tableA and tableB.name is a requirement.
Join on unrelated entities is not covered by latest JPA spec (2.1)
However Hibernate 5.1.0+ and EclipseLink 2.4.0+ support ad hoc joins. http://blog.anthavio.net/2016/03/join-unrelated-entities-in-jpa.html

Dynamic Named Query in Entity class using JPQL example

I have a named query as below;
#NamedQuery(name = "MyEntityClass.findSomething", query = "SELECT item FROM MyTable mytbl")
Now I want to append dynamic sort clause to this query (based on UI parameters)
Can I get an example using JPQL for doing the same (like how to set a dynamic ORDER BY in the Entity class)
I have already tried using CriteriaQuery, but was looking for a JPQL implementation now.
NamedQueries are by definition NOT dynamic, it is not correct to change them programmatically.
So the way to go is to create a JPQL query (but not a named query) like this:
TypedQuery<MyEntity> query = em.createdQuery("SELECT item FROM MyEntity item ORDER BY "+sortingCol, MyEntity.class);
On the other hand, if you REALLY want to use the named query, you could do that the following way:
#NamedQuery(name = "MyEntityClass.findSomething", query = MyEntity.NAMED_QUERY)
#Entity
public class MyEntity {
public static final NAMED_QUERY= "SELECT item FROM MyTable mytbl";
//+your persistent fields/properties...
}
//and later in your code
TypedQuery<MyEntity> query = entityManager.createQuery(MyEntity.NAMED_QUERY + " ORDER BY " + sortingCol, MyEntity.class);
Complementing for JPA 2.1
As of JPA 2.1 it is possible to define named queries programmatically.
This can be achieved using entityManagerFactory.addNamedQuery(String name, Query).
Example:
Query q = this.em.createQuery("SELECT a FROM Book b JOIN b.authors a WHERE b.title LIKE :title GROUP BY a");
this.em.getEntityManagerFactory().addNamedQuery("selectAuthorOfBook", q);
// then use like any namedQuery
Reference here
This can be useful, for instance, if you have the orderby field defined as a application parameter. So, when the application starts up or on the first run of the query, you could define the NamedQuery with the defined OrderBy field.
On the other side, if your OrderBy can be changed anytime (or changes a lot), then you need dynamic queries instead of NamedQuery (static). It would not worth to (re)create a NamedQuery every time (by performance).
#NamedQuery
Persistence Provider converts the named queries from JPQL to SQL at deployment time.
Until now, there is no feature to create/update the query with #NamedQuery annotation at runtime.
On the other hand, you can use Reflection API, to change the annotation value at runtime. I think It is not solution, also it is not you wanted .
em.createQuery()
Persistence Provider converts the dynamic queries from JPQL to SQL every time it is invoked.
The main advantage of using dynamic queries is that the query can be created based on the user inputs.

Categories