Is there a way to make these kind of query with multiple queries? - spring-boot

#Query("select user.id, language, profile " +
"from User user " +
"join user.language language " +
"left join user.profiles profile " +
"where user.id in :usersIds")
List<Object[]> findDataByUsersIds(#Param("usersIds") Collection<Integer> usersIds);
I would like a better way to write this query, by dividing it into multiple queries.

Related

Fetch specific column by using multiple tables, using native query and interface based projection

my need is to use native query and interface-based projection in JPA to fetch the record from multiple tables
#Query(value = "select cm.center_code as centerCode,cm.center_name as centerName,es.exam_slot_code as slotName,ecm.total_seat_allocated as seatAllocatedCount,ecityM.city_name as centerCity,afcatg.name as groupName from center_master cm "
+ "inner join centre_examslot_mapping cesm "
+ "on cm.center_id = cesm.centre_id "
+ "inner join exam_city_master ecityM "
+ "on ecityM.city_id= cm.center_city_id "
+ "inner join exam_slot es "
+ "on cesm.exam_slot_id= es.exam_slot_id "
+ "inner join exam_center_mapping ecm "
+ "on cesm.centre_examslot_mappingid = ecm.centre_examslot_mappingid "
+ "inner join afcat_group afcatg "
+ "on ecm.afcat_group_id= afcatg.afcat_group_id "
+ "where cm.center_code= ?1", nativeQuery = true)
public List<GetSlotGroupSeatAllocatedFromDB> getData(String centerCode);
To use projections you have to define an interface with attributes you need with prefix 'get'. Your class GetSlotGroupSeatAllocatedFromDB must be an interface implemented like this:
public Interface GetSlotGroupSeatAllocatedFromDB{
Integer getCenterCode();
String getCenterName();
String getSlotName();
Integer getSeatAllocatedCount();
String getCenterCity();
String getGroupName();
}
I supposed the attributes types (Integer o String, maybe your centerCode is String...)

Spring Boot complex Query

I am trying to create a method in the repository to be able to find out what is the most recent contract signed by an employee. The problem I have is that if I want to filter by the start date of the contract, I also have to pass it as a parameter and I don't have that, that's what I need. I tried this but the result is all contracts of this employee.
#Query(value = "SELECT * "
+ "FROM Contracts c "
+ "WHERE c.employeeName = :name "
+ "AND c.dateStartContract = ("
+ "SELECT MAX(dateStartContract) "
+ "FROM Contracts d "
+ "WHERE d.employeeName = :name)")
public Contract findByContractIDEmployeeName(#Param("name") String name);
What you can do is to do a query to find all and sort it using descending order:
List<Contract> findAllByOrderByIdDesc();
Then you can just pick the first item of the list and that will represent the most recent contract signed.
You can also append so you can find by a specific name only:
List<Contract> findAllByOrderByIdDescAndName(String name);
It might be some slight error in my code since I have not had the opportunity to test it.
The problem was that the import of #Query at the repository was import org.springframework.data.jdbc.repository.query.Query; and must be import org.springframework.data.jpa.repository.Query;.
After this change, the consult to data base is exactly my Query request.
My query is this.
#Query(value = "SELECT c "
+ "FROM Contract c "
+ "WHERE c.contractID.employeeName = :name "
+ "AND c.contractID.contractStartDate = ("
+ "SELECT MAX(contractID.contractStartDate) "
+ "FROM Contract d "
+ "WHERE d.contractID.employeename = :name)")
public Contract findByContractIDNameEmployeeAndByContractIDDateStartContract(#Param("name") String name);

Spring JPA - Issue while sorting on non entity column

I have requirement where I need to get the records based in join of three table with pagination(addition requirement are also there). So I have written a nativeQuery to get the records. Below is the sample query
#Query(value = "SELECT "
+ "a.GROUP_REF_ID as refId "
+ "count(case when c.STAT_CD in :userStatus then (c.grp_user_id) end) as numberOfUsers, "
+ "count(case when b.STAT_CD in :itemStatus then (b.grp_item_id) end) as numberOfItems "
+ "from grp a left join grp_item b on a.grp_id=b.grp_id left join grp_user c on a.grp_id=c.grp_id "
+ "where a.stat_cd in :status and a.co_id in :cids "
+ "group by a.GROUP_REF_ID,a.grp_nam,a.GRP_DESC,a.co_id,a.co_nam,a.CRTE_BY, "
+ "a.CRTE_DT,a.UPDT_BY,a.UPDT_DT ", countQuery = "select count(*) from grp where stat_cd in :status and co_id in :cids ", nativeQuery = true)
public Page<Object> findByStatusAndCompanyIdIn(#Param("status") String status, #Param("cids") List<Long> companyIds,
#Param("userStatus") List<GroupUserStatus> userStatus,
#Param("itemStatus") List<GroupItemStatus> itemStatus, Pageable pageable);
Now the requirement is also that these records are to be sorted on any of the column in select part. So, if user passes numberOfItems, the records are to be sorted on it. But I am facing an issue here because if I pass Sort parameter as numberOfItems, spring prepends an a. before numberOfItems which results in error that not able to find a.numberOfItems.
Is there a way I can stop spring from prepending table alias while creating a query with Sort, or should I write my logic in a different approach
Making my comment an answer so the question can be marked as answered:
Wrap the whole select in another one: select * from (<your current select>) x
I have solved the issue by creating a projection. (Kotlin was used but you’ll get the gist.)
class ShowRepository : JpaRepository<Int, Show> {
#Query("SELECT s AS show, (CASE WHEN (s.status = 'scheduled') THEN s.scheduledStartTime ELSE s.startTime END) AS time FROM Show s")
fun findShows(pageable: Pageable): Page<ShowWithTime>
}
interface ShowWithTime {
val show: Show,
val time: Date?
}
This allows Spring-Data to work its full magic, and using Sort.by(Order.desc("time")) works like a charm.
I’ve written it up with a little bit more detail here: Sorting by a Non-Entity Field.

How to perform left join in hql to fetch data

I am using following query to get data data database
String hql = "from Parameters s "
+"left join fetch s.userValues as uv "
+ "where s.groupId=:gid "
+"and uv.user.id=:uid " ;
Above is my hql query here I am fetching data from Parameter and from userValues.
This query is working properly if user have any value in userValues.
This query is not fetching any value when there is no saved value for user in userValues.
My problem is Whether there should be data in userValues or not I want to fetch data from Parameters.
How to achieve this using hql?
I just want to do left join in hql to get first table values.
You probably want something like this. You need to left join the association to user also. Note that you should use the Hibernate mapping between Parameter and Group as below. But you will probably need to use grouping to remove duplicate results.
String hql = "from Parameters s "
+ "join s.group g "
+ "left join fetch s.userValues uv "
+ "left join uv.user u "
+ "where g.id=:gid "
+ "and (u.id=:uid or u is null) ";

Spring Data JPA #Query with spel in a IN query

I work on Spring Data JPA and I have a repository interface which implements JpaRepository.
I have already written this query which works perfectly:
#Query ("FROM Person p " +
"LEFT JOIN p.relatedContractRoleAttributions rcras " +
"WHERE rcras.contract.id = :#{#contract.id} " +
"AND rcras.relatedContractRole.code = :#{#code}")
Person findByContractAndRelatedContractRole(#Param ("contract") Contract contract, #Param ("code") String code);
Now I want to write another query which can find in more than one code so I wrote this query:
#Query ("FROM Person p " +
"LEFT JOIN p.relatedContractRoleAttributions rcras " +
"WHERE rcras.contract.id = :#{#contract.id} " +
"AND rcras.relatedContractRole.code IN (:#{#codes})")
List<Person> findByContractAndRelatedContractRoles(#Param ("contract") Contract contract, #Param ("codes") String... codes);
But when I start my application I have this error:
Caused by: org.hibernate.QueryException: unexpected char: '#' [FROM com.krgcorporate.core.domain.access.Person p LEFT JOIN p.relatedContractRoleAttributions rcras WHERE rcras.contract.id = :#{#contract.id} AND rcras.relatedContractRole.code IN (:__$synthetic$__2)]
Do you have any idea why?
Thanks for your help.
I believe that there is an issue in org.springframework.data.jpa.repository.query.StringQuery. spring-data-jpa-1.7.2.RELEASE (lines 250..259)
case IN:
if (parameterIndex != null) {
checkAndRegister(new InParameterBinding(parameterIndex, expression), bindings);
} else {
checkAndRegister(new InParameterBinding(parameterName, expression), bindings);
}
result = query;
break;
So when StringQuery binds 'in' parameter with SPEL it overrides the result query string with the string in your #Query annotation. And then it replaces 'in' SPEL with the new binding.
If you change
"WHERE rcras.contract.id = :#{#contract.id} " +
"AND rcras.relatedContractRole.code in :#{#code}"
into
"WHERE rcras.relatedContractRole.code in :#{#code}" +
"AND rcras.contract.id = :#{#contract.id} "
it will fix your problem
UPDATE:
SpingDataJpa team has fixed it. https://jira.spring.io/browse/DATAJPA-712
For a JPA in clause you must not write brackets. (same question same answer here https://stackoverflow.com/a/4379008/280244)
#Query ("FROM Person p " +
"LEFT JOIN p.relatedContractRoleAttributions rcras " +
"WHERE rcras.contract.id = :#{#contract.id} " +
"AND rcras.relatedContractRole.code IN :#{#codes)")
And to be honest: I never have seen this syntax :#{#PARAM} before, I only know :PARAM. - but when it work in the other query is will work in the next one too
#Franck Yapadesouci Anso: according to your comment: are you sure that you can use the SPEL expressions in this way - try it the JPA way.
#Query ("SELECT p FROM Person p " + //+SELECT p
"LEFT JOIN p.relatedContractRoleAttributions rcras " +
"WHERE rcras.contract = :contract" + //without ID and SPEL
"AND rcras.relatedContractRole.code IN :codes") //without brackets and SPEL

Resources