Spring Boot complex Query - spring-boot

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);

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...)

How to query the database based on current day using Hibernate?

I would like to retrieve database items based on the current day.
For that purpose I am trying to use the day() function as explained there and mentioned there.
I have a 'created' date field that is automatically filled when a new item is created in the table. It's configured using a model, like that:
#Column(name = "created", nullable = false)
#CreationTimestamp
private Date created;
I created a couple of items and the date is filled in the database as expected.
Now I am trying to call those items using a HQL query:
String hql = "" +
"FROM Item as item " +
"WHERE item.itemId = ?1" +
"AND item.created = day(current_date())";
The problem is that this query is returning a NoResultException.
It's weird because I am using the current_date() function in other scenarios, e.g.:
String hql = "" +
"FROM Item as item " +
"WHERE item.itemId = ?1" +
"AND item.createdAt >= current_date - ?2";
And it is working pretty well!
So I assume the issue is related with day() function.
Try use this:
String hql = "" +
"FROM Item as item " +
"WHERE item.itemId = ?1" +
"AND date(item.created) = current_date()";

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

#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.

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.

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