Spring framework data JPA Inner Join on multiple columns - java

I would like to do the following query using spring jpa. I am able to build the where clause for my statement with Predicate.toPredicate. However, I don't know how to join on more than one column. On a single column it can be done in the repository using #Query and #Param
SELECT a.name, a.column_x, b.column_y
FROM table_a a
INNER JOIN table_b b
ON b.name = a.name
AND b.pk_2 = a.pk_2
AND b.pk_3 = a.pk_3
WHERE ...;
Another question I have is, is an intermediate tableA_tableB association beneficial if I have something like this, oneToMany relations.
Table 1: thing
thing_name
type
tenant
other1
other2
Table 2: thing_sub_prop
prop_name
value
Association table: thing_thing_sub_prop
type
thing_name
tenant
prop_name
value
Or is it better to just have two tables, thing and thing_sub_prop with the primary key columns of thing repeated in thing_sub_prop as a foreign key?

Related

JPA ManyToMany retreive 2 lists in one query

I need your help.
I've 2 tables with a join table to get ManyToMany relationship as below :
Table schema
In JAVA with JPA, I'm able for one User to get List<Group>, or for a Group to get List<User>.
Is there a way to get one entity with List<User> AND List<Group> like you can do with SQL :
SELECT * FROM USER_GROUP
INNER JOIN USERS ON USERS.ID = USER_GROUP.USER_ID
INNER JOIN GROUPS ON GROUPS.ID = USER_GROUP.GROUP_ID
WHERE USERS.USER_NAME LIKE ....
Thx all for your help :)

Spring Data JPA join 2 tables

I have 2 tables in MySQL database: user and user_additional_details with columns described below.
User
id (auto increment)
userId (unique)
first name
last name
phone
email
User Additional Details
id (auto increment)
userId (matches userId in User)
personalPhone
personalEmail
Table user_additional_details contains 0 or 1 row for each userId in user table.
However, database does not have a foreign key constraint defined. Ideally, columns from user_additional_details should have been added as nullable columns in user table, but that was not done for some unknown reason. Now I need to define the entity for following query.
select user.userId, user.phone, user_a_d.personalPhone
from user
join user_additional_details as user_a_d
on user.userId = user_additional_details.userId
I tried defining JPA entities for the tables, but not able to figure out how to create an entity that uses columns from different tables.
It seems like the SecondaryTable annotation is what you are looking for
Specifies a secondary table for the annotated entity class. Specifying
one or more secondary tables indicates that the data for the entity
class is stored across multiple tables.
Here you find a detailed example of how to use it - http://www.thejavageek.com/2014/09/18/jpa-secondarytable-annotation-example/
Create UserEntity (with all the columns from User table) and UserAdditionalDetailsEntity(with all the columns from user_additional_details table). I assume you are aware how to create JPA entities and map them to database table.
I hope you would have create entity manager factory object in your spring configuration file. With the help of that create entity manager object .
Once EntutyManager Object is created:
Query q= em.createQuery("select user.userId, user.phone, userDetails.personalPhone
from UserEntity user
join UserAdditionalDetailsEntity as userDetails
on user.userId = userDetails.userId");
List<Object[]> resultList= q.getResultList();
Once you get resultList you can iterate over the list of object array and get data.
Each index of the resultList will contain the object array representing one row
Keep in mind that field name mentioned in query should be same as the one mentioned in your JPA Entites.

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

How to retrieve all primary keys of a table using hibernate?

I need to retrieve all primary keys of a table and put them in a list.
Any method that I have found so far let me retrieve each record as an object, which force me to retrieve their primary keys separately and add them to the list.
Is there any other approach to retrieve the primary keys of a table and adding them to a list?
Using the following code hibernate returns objects but I need it to return a list of primary keys to store them in pk list.
List pk = new ArrayList():
Criteria criteria = session.createCriteria(MyTable.class, "mytable");
pk = criteria.list();
if mytable is as following
id name value
1 a z4
2 f o2
pk list should be
[1,2]
You can simply create an HQL query that returns the field you want:
session.createQuery("SELECT mt.id FROM MyTable mt").list();
assuming your primary key field is named id and MyTable is your entity. You can also do it with Criteria and Projections.
There are generally there ways to achieve that
1) Using Criteria API
2) Using HQL
3) Using Native Query
From the above hibernate queries way , better to us (1) and (2) , the 3rd way has dependency on the type of database.
1) Using Criteria API
Criteria criteria = session.createCriteria(MyTable.class, "mytable");
criteria.setProjection( Projections.projectionList().add( Projections.property("mytable.id"), "mytable.id"));
List<Long> ids=criteria.list();
2) Using HQL
Solution is already explained by Sotirious
3) Using Native Query
session.createSQLQuery(" SELECT mytable.id FROM MyTable mytable ").addScalar("ID","Hibernate.LONG").list();
Another approach is to use finder queries directly on repository(Spring JpaRepository) methods.
public interface MyRepository extends JpaRepository<MyTable, KeyType> {
#Query("select mt.id from MyTable mt")
List<KeyType> getAllIds();
}

Can you specify date-based partition keys when joining to related entities?

I have two related entities being mapped by JPA annotations backed by hibernate. The entities both have sequence-backed identity columns in oracle. Our also have monthly partitions, represented by a column called ENTRY_DATE.
T_MASTER T_JOINED
--------- -----------
MASTER_ID JOINED_ID
ENTRY_DATE ENTRY_DATE
MASTER_ID(FK)
... ....
To gain the benefit of the partition key, I'd like Hibernate to join on both the identity IDs and the partition key, but when I use the following annotation in the Joined class:
#ManyToOne
#JoinColumns(value={
#JoinColumn(name="MASTER_ID"),
#JoinColumn(name="ENTRY_DATE")})
private Master master;
I get errors about having too many join columns. I am forced to use
#JoinColumn(name="MASTER_ID")
private Master master;
I'm a bit of a JPA/Hibernate noob. Is it possible to use a partition key in addition to the primary key when joining to related entities?
Thanks!
You probably need to declare both columns as parts of composite primary key in Master. Hibernate would not care that much about what is real PK in the database. Mapping wil be slightly more complex with #Embeddable but it should solve the problem.
yes.
Using native sql it looks as follows:
Query query = session.createSQLQuery( "SELECT {T_master.*}, {T_joined.*} FROM schema.t_master AS T_master OUTER LEFT JOIN schema.T_joined AS T_joined ON T_master.ENTRY_DATE = T_joined.ENTRY_DATE AND T_master.MASTER_ID = T_joined.JOINED ID " /*WHERE ... */ );
query.setEntity( "T_master", T_master.class);
query.setJoin( "T_joined", "T_master.joinedSet"); //joinedSet is the one-to-many mapping
query.setJoin( "T_master", "T_joined.master" );
Thus, you get to be very verbose on your query, and hibernate only acts as an object mapper.
Using Criteria or HQL, it is impossible to have OUTER LEFT JOIN ON some field other than primary keys. This is why if you have such an option, use native SQL code.

Categories