Spring Data JPA : How to write subquery having IN operator - java

I am a new to Spring Data JPA, wanted to know how do I write the following subquery:
select o from Owner o where o.ownerId IN (Select c.ownerId from Cars c)
Here Owner is one entity class and Cars is another entity class and I'll be having two repositories one as OwnerRepository and the other as CarRepository, both extending JPARepository.
Help needed in writing this sort of custom queries with IN operator.
Thanks in advance.

You could always just use your query as a custom query:
#Query(value = "select o from Owner o where o.ownerId IN (Select c.ownerId from Cars c")
Owner getOwner();
If you need to pass variables to the query, use the #Param tag, like so:
#Query(value = "SELECT * FROM Owner o WHERE o.ownerId = :id")
Owner getOwnerWithId(#Param("id") Long id);

Related

Spring: How to get data from two table in JPA

In the following code I want to get the data from Order table and also from User table How can I modify my query so that I can achieve this ? user_id is foreign key in order table
public interface OrderRepository extends JpaRepository<Order, Long> {
#Query("Select o from Order o where o.customer.id= :customerId and o.orderStatus='DELIVERED'")
List<Order> orderHistory(#Param("customerId") long customerId);
}
To fetch the Customer with Order, do the join fetch.
The JOIN FETCH expression is not a regular JOIN and it does not define a JOIN variable. Its only purpose is specifying related objects that should be fetched from the database with the query results on the same round trip. Using this query improves the efficiency of iteration over the result Country objects because it eliminates the need for retrieving the associated Capital objects separately.
http://www.objectdb.com/java/jpa/query/jpql/from
public interface OrderRepository extends JpaRepository<Order, Long> {
#Query("Select o from Order o inner join fetch o.customer as customer left join fetch o.user as user where customer.id= :customerId and o.orderStatus='DELIVERED'")
List<Order> orderHistory(#Param("customerId") long customerId);
}
You want to put customerId and order fields into param?
I think list the order fields in params is enough.
of course sql statement must be right.

Using JPA native query with zero or more parameters

Goal: I am trying to build query via JPA which returns a list of locations, nearest to the coordinates passed to the query. The ability to apply filter(s), sort and paginate on the query are required. The following native SQL query is what I came come up with so far:
SELECT s.*
,sqrt(power(abs(:latitude-g.latitude),2)+power(abs(:longitude-g.longitude),2)) as d
FROM geolocations g
INNER JOIN salons s
ON g.zip=s.zip
WHERE LOWER(s.salon_name) LIKE LOWER(CONCAT('%',:q,'%'))
ORDER BY d asc limit
:pageSize offset :offset
Paganation, some sorting, and location based search are all working, but I cannot get filtering to work.
The filter requirement states that a user must also be able to filter search results(0 or more filters) by fields, like owner,state,zip... I want to use something like querydsl or the JPA Specification object to build a small query language but I cannot build out a working implementation given the fact that I am using a native query. I am looking for any recommendations on how I could implement the field filters into my existing repository.
Here is my entire repository:
public interface SalonRepository extends JpaRepository<Salon,String>, JpaSpecificationExecutor<Salon>{
#Query("select s from Salon s where s.city = :city and s.state = :state")
Page<Salon> findByCity(#Param("state")String state,#Param("city")String city,Pageable pageable);
#Query("select s from Salon s where s.salonName = :name")
Page<Salon> findByName(#Param("name")String name,Pageable pageable);
//THIS IS THE ONE I WANT TO ADD THE USER DEFINED FILTERS TO
#Query(value = "select s.*,sqrt(power(abs(:latitude-g.latitude),2)+power(abs(:longitude-g.longitude),2)) as d from geolocations g inner join salons s on g.zip=s.zip where LOWER(s.salon_name) like LOWER(CONCAT('%',:q,'%')) order by d asc limit :pageSize offset :offset", nativeQuery = true)
List<Salon> findNearest(#Param("latitude")float latitude,#Param("longitude")float longitude,#Param("q")String query,#Param("pageSize")int pageSize,#Param("offset") int offset);
#Query(value = "select sqrt(power(abs(:latitude-g.latitude),2)+power(abs(:longitude-g.longitude),2)) as d from geolocations g inner join salons s on g.zip=s.zip where LOWER(s.salon_name) like LOWER(CONCAT('%',:q,'%')) order by d asc", nativeQuery = true)
List<Float> findNearestInt(#Param("latitude")float latitude,#Param("longitude")float longitude,#Param("q")String query);
#Query("select s from Salon s where lower(s.salonName) like LOWER(CONCAT('%',:salonName,'%'))")
Page<Salon> findAll(#Param("salonName")String salonName,Pageable pageable);
}
After hours of searching, I am fairly certain I am on the wrong track given the lack of information I've uncovered.
Any and all help is appreciated!

Filter using field from child entity

I have class Person containing field age, Class Student extends Person containing field class, and class Teacher extends Person and containing field salary.
I want to get all Person who are in class X, if they are Student, and earn 1500$, if they are Teacher, using the same jpql query. The query must return a list of Person. I can make two query and make a method that call both query and join the result but is there a better solution.
I hope I was able to explain
Use "TYPE" and JPA 2.1 "TREAT" to filter on the class.
"SELECT p from Person p where treat(p as Teacher).salary = 1500 or TYPE(p) = Student"
If you cannot use JPA 2.1, you can use a subquery on Teacher to return Teacher ids with salary=1500, and use the result in the main query.
"SELECT p from Person p where p.id in(SELECT t.id from Teacher t where t.salary=1500) or TYPE(p) = Student"

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.

Categories