Hibernate: how can I specify left condition? - java

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"));

Related

Criteria with full join and left join

I am trying to write a query using the criteria class
select *
from A full join B on
A.aid=B.aid
left join C on
C.bid=B.bid
So far I have
criteria = getSession().createCriteria(A.class, "A")
.createCriteria("B", "B").createCriteria("C", "C")
which is a join on a inner join I do not want that
I figured it out.
criteria = getSession().createCriteria(A.class, "A", Criteria.LEFT_JOIN)
.createCriteria("B", "B").createCriteria("C", "C", Criteria.LEFT_JOIN);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

HQL merge two typedqueries

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.

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"

Hibernate Criteria Left Joining Two Tables

I have two entities, say Business and Area.
Relevant properties:
Business - area, area2, code
Area - areaId, areaName
area and area2 of Business map to the id in Area
I'm trying to write a Hibernate criteria that returns all the areas with businesses only.
SQL looks like:
FROM area a LEFT OUTER JOIN business b on a.areaId = b.area or a.areaId = b.area2
WHERE b.code != null
GROUP BY a.areaName
This is what I have:
DetachedCriteria criteria = DetachedCriteria.forClass(Business.class)
.setProjection(Property.forName("area"))
.setProjection(Property.forName("area2"))
.add(Restrictions.ne("code", null));
Criteria criteriaArea = fullTextSession.createCriteria(Area.class)
.createAlias("areaId", "areaId", CriteriaSpecification.LEFT_JOIN)
.add(Property.forName("areaId").in(criteria));
But this doesn't work, I get a "not an association: areaId" query exception.
Any ideas why this is happening? Thanks.
createAlias() joins another entity using provided property. Hibernate calculates what table to join using mapping of provided property. But areaId isn't mapped as a #ManyToOne or #ManyToMany reference to Business entity. So Hibernate doesn't understand to what table you want to join using Area.areaId.
Your criteria will be translated to SQL like:
select a.* from Area a
left join <here should be table referenced by areaId> b on a.areaId = b.id
where a.areaId in (
select area, area2 from Business where code <> null
)
You may rewrite query without unused join:
DetachedCriteria criteria1 = DetachedCriteria.forClass(Business.class)
.setProjection(Property.forName("area"));
DetachedCriteria criteria2 = DetachedCriteria.forClass(Business.class)
.setProjection(Property.forName("area2"));
Criteria criteriaArea = fullTextSession.createCriteria(Area.class)
.add(Restrictions.or(
Property.forName("areaId").in(criteria1),
Property.forName("areaId").in(criteria2)
);

Categories