Join two un-related tables using JPA EntityManager - java

I need to join two JPA entities on a property when there is no FK/PK relation between the two.
I am using Hibernate and can use HQL query like this
select foo, bar from FooEntity as foo, BarEntity as bar
where foo.someothercol = 'foo' and foo.somecol = bar.somecol
However, I want to avoid dependency on Hibernate and use EntityManager instead.
Please help.

Your query is valid JPQL and does not use Hibernate specific functionality (just space between bar and from is missing). In JPA 2.0 specification (4.4.5 Joins) this is explained with following words:
An inner join may be implicitly specified by the use of a cartesian
product in the FROM clause and a join condition in the WHERE clause.
In the absence of a join condition, this reduces to the cartesian
product.
The main use case for this generalized style of join is when
a join condition does not involve a foreign key relationship that is
mapped to an entity relationship. Example: SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize
Main difference to your query is that your select contains two types of entities. Result of query is List of Object[]. Order of elements in array is same as in select
statement. Following works in your case:
String query =
"select foo, bar from FooEntity as foo, BarEntity as bar "+
"where foo.someothercol = 'foo' and foo.somecol = bar.somecol";
List<Object[]> results = em.createQuery(query).getResultList();
for (Object[] fooAndBar: results) {
FooEntity foo = (FooEntity) fooAndBar[0];
BarEntity bar = (BarEntity) fooAndBar[1];
//do something with foo and bar
}

Related

Reverse types in JOIN query with JPA Criteria API

I would like to return a list of Group objects using a JPA criteria query. A group can either be empty or contain participants. Each Participant has a reference to its Group. The group knows nothing about the participants. Now I would like to implement a criteria query to dynamically return either:
Only groups with participants.
All groups (including empty ones).
Basically, this is my Group class:
public class Group {
private long id;
}
And this is my Participant:
public class Participant {
#ManyToOne
#JoinColumn(name = "FK_GROUP")
private Group group;
}
I left out all properties, methods and annotations for sake of simplicity.
This will return both, empty groups and groups with participants, in plain SQL:
SELECT DISTINCT G.* FROM GROUP_TABLE G
LEFT JOIN PARTICIPANT_TABLE P ON P.FK_GROUP=G.ID;
Now I'd like to do the same thing with Criteria API:
if (includeEmptyGroups) {
// ...
Root<Group> root = criteria.from(Group.class);
Join<Participant, Group> join = root.join("id"); <-- This is my issue!
criteria.select(root).distinct(true);
//...
}
else {
// ...
}
The query should return a list of Group objects, so I chose that type for my Root object and the from() method. Now, most tutorials would define a Join<Group, Participant>, and join participants by a property of the Group class.
Due to my reversed class structure, however, I cannot do this. The code above does not work, because I reversed the types and JPA cannot join by simple types. I'm unsure, if I approach the problem correctly at all.
I could switch types around and base my Root on the Participant class, then join with Group. This, however, makes it impossible to conditionally return empty groups. Is it even possible to build the plain SQL query with Criteria API?
Since the JPA contracts do not allow for left joining entities, you can only use HQL or a query builder API on top of HQL like e.g. Blaze-Persistence which supports this. Either way, you will need at least Hibernate 5.1 which is the first version that added support for entity joins.

Map sql query result to java object(in Non-Entity class) using spring jpa

I want to assign SQL query result to Java object which is in non-entity class.
My query is counting the number of records in Table A mapped to another Table B.
#Query(value="select count(a.id) from table1 a join table2 b on a.id=b.id group by a.id", nativeQuery=true)
Non-Entity class
public class Sample {
//assign query result to count variable
private long count;
// getters and setters
}
A and B are Entity class, I'm selecting specified columns of Entity A and B and including that columns in Sample.class and sending data as JSON on REST call.
Now my question is to assign count result to count variable.
Thanks in advance
How to do a JPQL query using a "group by" into a projection (Non-Entity-Class)?
Scenario you have two tables: User and User_Role and you want to know how many users in your system has the "public" role and how many have the "admin" role (Any other roles too if present).
For example: I want a query that will let me know there are two users that have "public" role and one user has the "admin" role.
Simplest Example:
#Query("SELECT ur.roleName, count(u.id) from User u left join u.userRole ur group by ur.roleName")
List<Object[]> getCounts();
In this case dealing with the result is more complicated then you typically would want. You would have to iterate over both the list and array of Objects.
Query into a projection Example:
#Query("SELECT new com.skjenco.hibernateSandbox.bean.GroupResultBean(ur.roleName, count(u.id)) from User u left join u.userRole ur group by ur.roleName")
List<GroupResultBean> getCountsToBean();
This would give you a List that is much better to work with.
Code Example: https://github.com/skjenco/hibernateSandbox/blob/master/src/test/java/com/skjenco/hibernateSandbox/repository/UserProjectionExampleTest.java

criteria query: indistinct result lists

I have 2 little problems. Let's say I have an entity class called MyEntity. This class has two kinds of properties. Therefore I have two different class Property1 and Property2 which are also entity classes. There are bidirectional relations betweens MyEntity and the property classes, especially Property1 has an attribute List<MyEntity> owningEntities and Property2 has the attribute MyEntity owningEntity. Now I have the following query:
SELECT e FROM Property1 p JOIN p.owningEntities e WHERE p.name IN :propertyNames
This query returns all entities that has a property of the first type with at least one of the given names. But in general the returned list is indistinct. The problem is that the SELECT DISTINCT downs't work here, at least with criteria API - I didn't try it with jpql. The code for the criteria query looks as follows:
CriteriaQuery<MyEntity> cq = cb.createQuery(MyEntity.class);
Root<Property1> property = cq.from(Property1.class);
SetJoin<Property1, MyEntity> entity =
property.join(Property1_.owningEntities);
cq.where(property.get(Property1_.name).in((Object[]) propertyNames));
cq.select(entity);
// cq.select(entity).distinct(true); --> runtime error
List<MyEntity> resultList = em.createQuery(cq).getResultList();
Is there any way to get a distict result list? I can simply convert the list into a set, but it seems ineffective to extract the same results multiple times.
The next problem is, of course I want all entities that has a property of the any type with at least one of the given names. Until now I have two queries and afterwards I merge the results. But again I extract many results multiple times. So, is there any way to combine the following two queries in an effective way?
SELECT e FROM Property1 p JOIN p.owningEntities e WHERE p.name IN :propertyNames
SELECT e FROM Property2 p JOIN p.owningEntity e WHERE p.name IN :propertyNames
Thanks in advance!

How to write a JPA query with an "order by" clause against a property that may be null

I have defined a JPA entity "A" with a #ManyToOne relationship to another JPA entity "B".
#Entity
class A {
String name;
int sortOrder
#ManyToOne
B b;
}
This reference can be null or it can be populated. Now, I would like to query all the As and sort by B.name. Unfortunately, something like
find("order by B.name, sortOrder, name")
seems to drop any As such that (A.b = null). What is the best way to write this query?
I want all the As and I want them sorted by their B.name reference if it exists ... lumping all those with no B property together.
you need a left join.
select a from A a left join a.b b order by b.name, a.sortOder, a.name
or something like that.
There are several approaches … Sets/Comparators, HQL, Native Sql, #Sort annotations …

hibernate and jpa weirdness; unexpected lazy fetching

I'm using a rather old version of Hibernate (3.2.4) so it's possible this is related to that. Unfortunately the project requirements prevent me from upgrading.
I have a class Foo with many-to-one association to Bar. The association is flagged:
lazy="false" fetch="join"
Now when I do something like:
em.find(Foo.class, id);
I get the expected result: a single statement joining the FOO table with the BAR table. However, when I try something like:
em.createQuery("select f from Foo where f.id = :id")
.setParameter("id", id)
.getSingleResult();
I get the single join followed by an additional select query against BAR. The second query seems to be entirely superfluous; all the data needed to eagerly populate an instance of Foo should have been available from the initial join. It looks roughly like this:
select f.id, f.xyz, ..., b.id, b.xyz, ...
from foo f
join bar b on b.id = f.bar_id
where f.id = ?
select b.id, b.xyz, ...
from bar b
where b.id = ?
Any thoughts?
Hibernate doesn't respect fetch = "join" when executing HQL queries. From the documentation:
The fetch strategy defined in the mapping document affects:
retrieval via get() or load()
retrieval that happens implicitly when an association is navigated
Criteria queries
HQL queries if subselect fetching is used
In the case of HQL queries you have to use left join fetch:
em.createQuery("select f from Foo f left join fetch f.bar where f.id = :id")
.setParameter("id", id)
.getSingleResult();

Categories

Resources