In my #Entity annotated Course class, I have the following #ElementCollection annotated map:
#ElementCollection
private Map<Student, Double> courseStudAndAvgStudGrade;
In the example above, Student is another #Entity annotated class and the value is the average grade from a Course for each Student. I'm trying to write a query in JPQL that would retrieve all the entries of this map and sort by entry value in descending order.
So far, I have the following:
TypedQuery<Tuple> query =
em.createQuery("SELECT KEY(map), VALUE(map) "
+ "FROM Course c JOIN c.courseStudAndAvgStudGrade map WHERE c.id = :id", Tuple.class);
This retrieves the values correctly in a Tuple for the desired Course, however adding ORDER BY VALUE(map) DESC to the JPQL query results in a java.sql.SQLException: Subquery returns more than 1 row.
Is it possible to do ORDER BY on a map in JPQL?
JPA/Hibernate does not require the VALUE qualifier i.e. it's actually just there for completeness. Try the following query:
em.createQuery("SELECT KEY(map), map FROM Course c JOIN c.courseStudAndAvgStudGrade map WHERE c.id = :id ORDER BY map DESC", Tuple.class);
Related
I have this query in JPA:
#Query("SELECT programId,COUNT(id) FROM Therapy GROUP BY programId ORDER BY COUNT(id) DESC")
List<Object> top10ProgramsOfTherapies();
It works great, but it returns a list of Objects, and I can not get the data out of it. What return type should I use to read the result data?
You can also create a DTO class, for example, TherapyDto which will have a constructor with 2 parameters and use it this way:
#Query("SELECT new com.my.TherapyDto(programId,COUNT(id)) FROM Therapy GROUP BY programId ORDER BY COUNT(id) DESC")
List<TherapyDto> top10ProgramsOfTherapies();
This query will return a list of objects array: Object[] so you need to change your code like this:
#Query("SELECT programId,COUNT(id) FROM Therapy GROUP BY programId ORDER BY COUNT(id) DESC")
List<Object[]> top10ProgramsOfTherapies();
And for each item in the list : item[0] will hold the programID value and item[1] will hold the COUNT(id) value, and you should cast them to their respective types as they will be just objects.
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.
I do have a query need to customize but i need to maintain the pagination and sorting function. Is there any possible to point when call .findAll to my NamedNativeQuery?
call findAll
Page<Customer> page = customerDao.findAll(specifications,
new PageRequest(pageNo, limit, Utils.jasonToSort(sorts)));
my NamedNativeQuery (the query statement will come with union join)
#Entity
#Table(name = "Customer")
#NamedNativeQueries({
#NamedNativeQuery(
name = "Customer.findAll",
query = "SELECT ID, Customer_Name, Customer_DESC FROM Customer WHERE Customer_Name = :Cust_Name") })
Actually my actual query is more complex with Union join, and parameter.
Is there a way to point .findAll to the NamedNativeQuery and pass in a parameter?
Thank You
I have an unidirectional relationship. Here i have Employee and Andress entities. In Employee entity i have the following code:
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "HOME_ADDRESS")
private Address homeAddress;
I have an array of Adress objects and want to write a lookup that would return an array of Customer objects mapped to those adresses.
select e from Employee e where e.homeAddress.id IN '?'
I don't know what to do with the '?' part. Is the only option to loop over the address array, add id's to a string and pass it as a parameter to the query above, or is there a way to pass the array to the query and expect the same result?
No, you don't pass that as a String, but as a collection of IDs. And your query is invalid. It should be:
String jpql = "select e from Employee e where e.homeAddress.id IN :addresses";
Set<Long> addressIds = Arrays.stream(addresses)
.map(Address::getId)
.collect(Collectors.toSet());
return em.createQuery(jpql, Employee.class)
.setParameter("addresses", addressIds)
.getResultList();
This uses Java 8 to transform the array of addresses into a set of IDs, but you can of course use a goold old for loop.
2 Solutions:
HQL
String hql="select e from Employee e where e.homeAddress.id IN (:addresses)";
Query query = getSession().createQuery(hql);
query.setParameterList("addresses", your_list_address_collection);
Criteria
Criteria criteria = session.createCriteria(Employee.class);
criteria.add(Restrictions.in("addresses", your_list_address_collection));
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.