I am currently developing the search and filtering feature of my project. I am trying to retrieve data with this Request body:
{
"researchers": [
"Jhon Doe"
],
"unit": null,
"agency":null,
"date": null,
"status": null,
"budget": null
}
and below is the method from the ReasearchRepository that retrieves this data:
#Query("select r from Research r " +
"left join r.fundingAgencies fundingAgencies " +
"left join r.researchers researchers " +
"where (:budgetStart is null or :budgetEnd is null or r.budget between :budgetStart and :budgetEnd )" +
"and (:startDate is null or r.startDate >= :startDate) " +
"and (:endDate is null or r.endDate <= :endDate) " +
"and (:agencyNames is null or fundingAgencies.agencyName in :agencyNames) " +
"and (:unitNames is null or r.deliveryUnit.unitName in :unitNames )" +
"and (:names is null or researchers.name in :names ) " +
"and (:researchStatuses is null or r.researchStatus in :researchStatuses)")
List<Research> findAdvanced( #Param("budgetStart") Double budgetStart,
#Param("budgetEnd") Double budgetEnd,
#Param("startDate") LocalDate startDate,
#Param("endDate") LocalDate endDate,
#Param("agencyNames") Collection<String> agencyNames,
#Param("unitNames") Collection<String> unitNames,
#Param("names") Collection<String> names,
#Param("researchStatuses") Collection<ResearchStatus> researchStatuses);
My problem is when I'm trying to find data from given values in the request, it returns an empty list [] even though it exists in the database. What I want to achieve is that if the parameter is null, it will ignore a specific condition in the query and will still return data.
I just followed the article from Baeldung.
I also find another article about using Criteria API, but it will take a lot of time for me to understand that. My project is a bit rush.
TIA
I seems like a good case to use Specifications.
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
Related
I am using JPA-Hibernate in our application and I am working with a query like :
#Query(
value = "ReportDTO(report) FROM Report report " +
"JOIN p.clientFile cf " +
"JOIN cf.client cl " +
"WHERE report.active = TRUE " +
"AND :companyKey = CASE WHEN report.companyKey IS NOT NULL " +
"THEN report.companyKey " +
"ELSE cl.companyKey " +
"END " +
"ORDER BY report.publishedDate DESC",
countQuery = “..”
)
#NonNull
Page<TagReportDTO> findAll(#NonNull Pageable pageable, #Param("companyKey") String companyKey);
when the "companyKey" was a single value, it worked. Now, I need to change this findAll method to accept a list of company keys. So it should like like ( after the change) :
#NonNull
Page<TagReportDTO> findAll(#NonNull Pageable pageable, #Param("companyKeys") List<String> companyKeys);
Now I am getting hard time to accommodate the list of objects or companyKeys (instead of :companyKey) in the query where the the case statement will be applicable to each item in the list. Is there a way I can loop through ?
Did you try using IN operator? Like this:
"AND (CASE WHEN report.companyKey IS NOT NULL " +
"THEN report.companyKey " +
"ELSE cl.companyKey " +
"END) IN :companyKeys "
i am trying to update rows with optional parameters, but i am getting error with below query.
#Modifying
#Transactional
#Query("UPDATE Visit visits SET "
+ " visits.approvalStatus is null OR visits.approvalStatus = :approvalStatus "
+ " , visits.declineReason is null OR visits.declineReason =:declineReason "
+ " WHERE visits.visitId in :visitIds ")
public int patchUpdate(#Param("approvalStatus") String approvalStatus,
#Param("declineReason") String declineReason, #Param("visitIds") List<Integer> visitIds);
error logs :
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: expecting EQ, found 'is' near line 1, column 69 [UPDATE com.quest.vms.entity.Visit visits SET visits.approvalStatus is null OR visits.approvalStatus = :approvalStatus WHERE visits.visitId in :visitIds ]
Edited to add info : here i want to update a particular field when new data is not null, otherwise that parameter should be ignored.
Thanks for your help
is null is used for checking the field.
For setting column on the basis of condition you can use:
UPDATE Visit visits SET "
+ " visits.approvalStatus = CASE "
+ " WHEN visits.visitId in :visitIds THEN :approvalStatus "
+ " ELSE NULL "
+ " END"
There is a syntax error in the UPDATE query, the part to set a field value is missing.
Possibly a query using COALESCE function (or a native query using functions such as IsNull, NullIf, NVL) could be helpful:
#Query("UPDATE Visit visits SET "
+ "visits.approvalStatus = COALESCE(:approvalStatus, approvalStatus) "
+ "visits.declineReason = COALESCE(:declineReason, declineReason) "
+ " WHERE visits.visitId in :visitIds")
public int patchUpdate(
#Param("approvalStatus") String approvalStatus,
#Param("declineReason") String declineReason,
#Param("visitIds") List<Integer> visitIds
);
Or using similar CASE statement
#Query("UPDATE Visit visits SET "
+ "visits.approvalStatus = (CASE :approvalStatus WHEN NULL THEN approvalStatus ELSE :approvalStatus END) "
+ "visits.declineReason = (CASE :declineReason WHEN NULL THEN declineReason ELSE :declineReason END) "
+ " WHERE visits.visitId in :visitIds")
public int patchUpdate(
#Param("approvalStatus") String approvalStatus,
#Param("declineReason") String declineReason,
#Param("visitIds") List<Integer> visitIds
);
You can add a case condition while setting data like
UPDATE
Visit visits
SET
visits.approvalStatus = (
case
when :approvalStatus is null
then visits.approvalStatus
else :approvalStatus
end
),
visits.declineReason = (
case
when :declineReason is null
then visits.declineReason
else :declineReason
end
),
WHERE visits.visitId in :visitIds
If passed value is null, you set the value you have in db, otherwhile set the passed value.
I'm running a native query on spring boot jpa with Postgresql/PostGIS.
The query is running fine on postgresql:
WITH data AS (SELECT '{ "type": "Point", "coordinates": [102.0, 0.5]
}'::jsonb AS fc)
UPDATE dopigp.disciplinare_aree SET area_da_validare=(
SELECT
ST_Union(ST_AsText(ST_GeomFromGeoJSON(feat->>'geometry'))) AS geom
FROM (
SELECT
CASE
WHEN fc ? 'features' THEN jsonb_array_elements(fc->'features')
WHEN fc ? 'geometry' THEN (fc)
ELSE jsonb_build_object('geometry', fc)
END
AS feat
FROM data
) AS f
) WHERE id_disciplinare=251
On Spring Boot give me the error: Mixing of ? parameters and other forms like ?1 is not supported
#Transactional
#Modifying
#Query(value = "WITH data AS (SELECT (?2)\\:\\:jsonb AS fc)\n" +
"UPDATE dopigp.disciplinare_aree SET area_da_validare=(\n" +
"SELECT\n" +
" ST_Union(ST_AsText(ST_GeomFromGeoJSON(feat->>'geometry'))) AS geom\n" +
"FROM (\n" +
" SELECT \n" +
" CASE \n" +
" WHEN fc ? 'features' THEN jsonb_array_elements(fc->'features')\n" +
" WHEN fc ? 'geometry' THEN (fc)\n" +
" ELSE jsonb_build_object('geometry', fc)\n" +
" END \n" +
" AS feat\n" +
" FROM data\n" +
") AS f\n" +
") WHERE id_disciplinare=(?1) \n",
nativeQuery = true)
void upload(Integer idDisciplinare, String geoJSON);
You have to escape the ? in the case statement because this is the parameter placeholder but instead of \ you have to use ? :
WHEN fc ??
Seems like it's not possible to escape the question mark.
So the only solution was to create a custom operator to substitute the question mark as pointed here and use it in the native query instead of "?".
I am trying to write a query that performs a search according to several criteria.
My current JPA request:
#Query("SELECT c FROM Client c " +
"INNER JOIN c.entite e " +
"WHERE e.numeroLicence in (:numerosLicence) " +
"AND (UPPER(c.nom) LIKE CONCAT('%',UPPER(:nom),'%') " +
"AND (c.prenom IS NOT NULL AND UPPER(c.prenom) LIKE CONCAT('%',UPPER(:prenom),'%')) " +
"AND (c.dateCreation IS NOT NULL AND c.dateCreation > :dateCreation) " +
"AND (c.dateCreation IS NOT NULL AND c.dateModification > :dateModification) " +
"AND (c.dateCreation IS NOT NULL AND c.dateSuppression > :dateSuppression)) ")
Page<Client> recherche(#Param("numerosLicence") ArrayList numerosLicence,
#Param("nom") String nom,
#Param("prenom") String prenom,
#Param("dateCreation") ZonedDateTime dateCreation,
#Param("dateModification") ZonedDateTime dateModification,
#Param("dateSuppression") ZonedDateTime dateSuppression,
Pageable pageable);
The problem is that it automatically excludes rows where a column contains NULL.
I'll need the selection to be done on columns with data only, it will not try to execute the clause if the field value is NULL
For example, if I have a row whose firstname column is NULL, then this line is automatically excluded from the result whereas I would like it not to test this column if it is NULL
Do you have an idea?
I'm looking for a solution to avoid creating as many queries as possible combination
Sounds like you should use OR instead of AND:
c.dateCreation IS NULL
OR c.dateCreation > :dateCreation
#Query(value = "Select f from Documents f " +
"RIGHT JOIN f.documentStatus ds " +
"where f.billingAccount.accountId in :billingAccountIdList " +
" and ds.statusCode in :paymentStatuses" +
" and f.paymentDate < :paymentDate")
List<FinancialDocumentEntity> getFinancialDocumentsOverdue(#Param("billingAccountIdList")List<String> billingAccountIdList,
#Param("paymentStatuses") List<String> paymentStatuses,
#Param("paymentDate") Date paymentDate);
I have query like above. It is possible to skip searching param for example #Param("paymentStatuses") in query method if is null or is empty ?
Try changing
" and ds.statusCode in :paymentStatuses"
into
" and (:paymentStatuses is null or ds.statusCode in :paymentStatuses)"
Try changing
" and ds.statusCode in :paymentStatuses"
into
" and (COALESCE(:paymentStatuses, null) is null or ds.statusCode in :paymentStatuses)"
This solution will work for the empty list, null list, and a list with items 1 or more.