HQL merge two typedqueries - java

I have written two hibernate queries:
TypedQuery q = em.createQuery("SELECT user.id FROM TableOne AS user WHERE ...", Long.class);
TypedQuery q = em.createQuery("SELECT link.user_id FROM TableTwo AS link WHERE ...", Long.class);
Now, how do I merge these two queries? My return type has to be TypedQuery

the UNION statement not work on Hibernate.
So you can:
Execute first query and put in a list;
Execute second query and put in a list;
Put the result of first and second list in a unique list.
If you want to delete the duplicated value, you must do programmatically.

Completely copying answer from https://stackoverflow.com/a/3940445/929701:
You could use id in (select id from ...) or id in (select id from ...)
e.g. instead of non-working
from Person p where p.name="Joe"
union
from Person p join p.children c where c.name="Joe"
you could do
from Person p
where p.id in (select p1.id from Person p1 where p1.name="Joe")
or p.id in (select p2.id from Person p2 join p2.children c where c.name="Joe");
At least using MySQL, you will run into performance problems with the later though. It's sometimes easier to do a poor man's join on two queries instead:
// use set for uniqueness
Set<Person> people = new HashSet<Person>((List<Person>) query1.list());
people.addAll((List<Person>) query2.list());
return new ArrayList<Person>(people);
It's often better to do two simple queries than one complex one.

Related

HQL left join with condition

This may seem basic but it's late and I'm having trouble with the following.
class Group {
#Id
String id;
}
class Participation {
#Id
String id;
#ManyToOne
#JoinColumn(name = "GROUP_ID")
Group group;
#ManyToOne
#JoinColumn(name = "USER_ID")
User user;
}
class User {
#Id
String id;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
Set<Participation> participations;
}
Class diagram
So
Participation -->1 Group
and User 1<-->N Participation
How can I retrieve all Groups with, for a given User, the associated Participation (or null is there is none)? I've been playing with join fetches but to no avail so far...
Many thanks,
CN
PS. I can do this in SQL thus :
select g.d, p.id
from group as g
left join participation as p
on p.group_id = g.id and p.user_id = 2;
(Probably some typo in the HQL itself but the idea should be correct)
What you are asking, based on your SQL and description, is find out all Participation (and its corresponding Group) based on User, which is simply
select p.id, p.group.id from Participation p where p.user.id = :userId
To make it better, you should fetch the entities instead:
from Participation p left join fetch p.group where p.user.id = :userId
There were some confusions in understanding what you were trying to do:
You want all groups (regardless of condition). And, for a given user, you want to find all groups and participations that user is involved.
Though it should be possible using Right-outer-join:
select g, p from Participation p
right outer join p.group g
where p.user.id=:userId
Or, in later version of Hibernate (>= 5.1 ?), it allow explicit join (haven't tried before, you may give it a try) (Replace with with on if you are using JPQL):
select g, p from Group g
left outer join Participation p
with p.group = g
left outer join p.user u
where u.id = :userId
Or you may use other techniques such as subquery etc. However I would rather separate them into simpler queries in your case and do a simple aggregation in your code.
The basic idea is to have
Query for all groups: from Groups
Query for all participations for a user: from Participation p join fetch p.group where p.user.id=:userId
Then you can aggregate them easily to the form you want, e.g. Map<Group, List<Participation>>, or even more meaningful value object.
The benefit is the data access query is simpler and more reusable (esp if you are wrapping them in DAO/Repository finder method). One more round trip to DB shouldn't cause any obvious performance impact here.
You need to map the participation relationship in the Group entity. If the relationship between Participation and Group is 1..N:
class Group {
String id
List<Participation> participations
}
The JPQL can be:
SELECT g.id, p.id FROM Group g
JOIN g.participations p
JOIN p.user user
WHERE user.id = :idUser
You can receive this information as List<Object[]> (Object[0] is group id and Object[1] is participation id) or use SELECT NEW.
Without map the Group/Participation relationship, you can do:
SELECT g.id, p.id FROM Group g, Participation p
JOIN p.user user
JOIN p.group groupp
WHERE g.id = groupp.id
AND user.id = :idUser
But you can't do a LEFT JOIN using this strategy. The query above behaviours like a JOIN.
It's normal with Hibernate you map the side of a relationship that you would like to make a query. So, I recommend the first approach, mapping the relationship.

Hibernate: how can I specify left condition?

I've two tables:
The table A named "Prova" has the following columns: id, id_comitato, id_comitato_erog
The table B named "comitato" has the following columns: id_comitato, name
Criteria:
Criteria criteria = mySession.createCriteria(Prova.class, "p");
criteria.createCriteria("comitato", "c", CriteriaSpecification.LEFT_JOIN);
Translate this query in SQL is:
SELECT * FROM Prova p LEFT JOIN comitato c ON p.id_comitato=c.id_comitato
But what I want is the following:
SELECT * FROM Prova p LEFT JOIN comitato c ON p.id_comitato_erog=c.id_comitato
How can I specify this join condition?
Thank you very much,
have a good day!
Have you tried something like this -> Yet another post on Stackoverflow
.Basically you would have to do something similar to the following:
Criteria criteria =
mySession.createCriteria(Prova.class, "p")
.createAlias("comitato",
"c",
Criteria.LEFT_JOIN,
Restrictions.eqProperty("p.id_comitato_erog",
"e.id_comitato"));

What is the object type returning in a join of a hibernate query

When I have the below query it will give me a list of Product.
List<Product>=
getCurrentSession().createQuery("SELECT p FROM Product p ").list();
What will it return when there is a join as below.
getCurrentSession().createQuery("SELECT p FROM Product p inner join ProductCategory pc where p.id=pc.id").list();
It should return List<Object[]> as a result. Please see this thread
And you should access your entities like
for (Object[]> result : query.list()) {
Product p = (Product) result[0];
ProductCategory pc = (ProductCategory) result[1];
}
SELECT p FROM Product p inner join ... something like that gives you a list of Products.
FROM Product p inner join ... something like that gives you a list of arrays.
This will return a list of objects. You will have to cast them in to Product
List list = session.createQuery("SELECT p FROM Product p inner
join ProductCategory pc where p.id=pc.id").list();
According to the documentation for javax.persistence.Query, you are going to get a List back. Why would you think it should be different?
This class casting from java.lang.object to model class doesn't work in any ways. Below is my code.
List<Contactinfo> listStudentInfo = new ArrayList<Contactinfo>();
//listStudentInfo = dataService.getAllStudent(studentInfo);
listStudentInfo = dataService.getStudentInfo();
System.out.println(listStudentInfo.size());
Contactinfo contactinfo = (Contactinfo)listStudentInfo.get(0);
But In hibernate, you don't need join if you have both Entity associated with by #Many-to-one or #One-to-one join annotation. Then you need to select one object only , you will automatically get access to other object via the join. Make sure you keep getter(), setter() method for the joining field. Hope this will clarify the situation.

How to create a JPA query with LEFT OUTER JOIN

I am starting to learn JPA, and have implemented an example with JPA query, based on the following native SQL that I tested in SQL Server:
SELECT f.StudentID, f.Name, f.Age, f.Class1, f.Class2
FROM Student f
LEFT OUTER JOIN ClassTbl s ON s.ClassID = f.Class1 OR s.ClassID = f.Class2
WHERE s.ClassName = 'abc'
From the above SQL I have constructed the following JPQL query:
SELECT f FROM Student f LEFT JOIN f.Class1 s;
As you can see, I still lack the condition OR s.ClassID = f.Class2 from my original query. My question is, how can I put it into my JPQL?
Write this;
SELECT f from Student f LEFT JOIN f.classTbls s WHERE s.ClassName = 'abc'
Because your Student entity has One To Many relationship with ClassTbl entity.
If you have entities A and B without any relation between them and there is strictly 0 or 1 B for each A, you could do:
select a, (select b from B b where b.joinProperty = a.joinProperty) from A a
This would give you an Object[]{a,b} for a single result or List<Object[]{a,b}> for multiple results.
Normally the ON clause comes from the mapping's join columns, but the JPA 2.1 draft allows for additional conditions in a new ON clause.
See,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#ON
Please see :
public interface YourDBRepository extends JpaRepository<Employee, Long> {
#Query("select new com.mypackage.myDTO(dep.empCode, dep.empName, em.EmployeeCode, em.EmployeeName) \n" +
"from Department dep\n" +
"left join Employee em\n" +
"on dep.DepartmentCode = em.DepartmentCode") // this is JPQL so use classnames
List<myDTO> getDeptEmployeeList();
}
You can also use CrudRepository and include #JoinColumn with FK table class in PK table class and have List return list and then do find operation to achieve the same.
In Department entity class:
#OneToMany
#Fetch(FetchMode.JOIN)
#JoinColumn(name="DEPT_CODE")
private List<Employee> employees;
CriteriaBuilder is yet another option.

Hibernate left join fetch - get only an ID list of the first table

I have the following HQL query which works fine, however it returns a list of full FooD objects. I only need the ID of the FooD objects as I need to have faster query. Please not that in Hibernate mappings, FooD has a many-to-one relationship with FooB.
hqlQuery = "from FooD d left join fetch d.bill where d.ts < :ts"
I have then tried to get only the ID using the same kind of HQL query:
hqlQuery = "SELECT d.id from FooD d left join fetch d.bill where d.ts < :ts"
I got a "query specified join fetching, but the owner of the fetched association was not present in the select list".
I have then converted the query to regular Oracle SQL to get only FooD.ID:
sqlQuery = "SELECT d.id from FooD d LEFT OUTER JOIN FooB b on d.foodId=b.id where d.ts < :ts"
I have then mapped FooD and FooB objects like this:
sqlQuery.addEntity(FooD.class);
sqlQuery.addEntity(FooB.class);
and then get the resulting list by calling:
hSession.createSQLQuery(sql).setTimestamp("ts", ts).list();
But got the following error: "unexpected token: on near line 1".
Does someone know how to do get only the ID of FooD when doing a left outer join on FooB using Hibernate?
Update:
I didn't test it, but this should do the trick
SELECT d.id from FooD d inner join d.bill where d.ts < :ts
when you add LEFT you make it an outer join implicitly, and there is no need to initialize bill if all you need is to join by keys
Hibernate requires the object to be in the select clause to do any eager join fetches on it
But since you have no select or where clauses on d.bill, why do you need to fetch it anyway?
If all you need is the id, why not do this, there is no reason for the redundant join:
hqlQuery = "SELECT d.id from FooD d where d.ts < :ts"

Categories