How to get data based on 'AND' operator instead of 'LIKE' by using JpaSpecificationExecutorWithProjection's findAll method? - java

I am new to Hibernate.My senior used 'findAll' method of JpaSpecificationExecutorWithProjection (interface) which is returning result based on a 'LIKE' operator but I required result based on 'AND' operator. Please guide me how I can solve this?.
Below is the part of code which displays it is hitting query based on 'LIKE' operator
where
(
upper(course0_.course_subject) like ?
)
and (
upper(course0_.course_sub_category) like ?
)
and course0_.course_status=?
and (
upper(course0_.course_exam_segment) like ?
)
and (
upper(course0_.course_category) like ?
)

It is using AND operator. The LIKE is for evaluating your individual params.
If you don't like the JPA-methodqueries, you can always write your own in your repository. Below is a quick example incorporating a left join and returning a Page-object. Please take a look here for some basic JPQL
#Query("SELECT p FROM Product p "
+ "LEFT JOIN p.categories category "
+ "WHERE UPPER(p.name) LIKE UPPER(CONCAT('%', COALESCE(:searchRequest, ''), '%')) "
+ "AND UPPER(p.description) LIKE UPPER(CONCAT('%', COALESCE(:description, ''), '%')) "
+ "AND p.price BETWEEN :priceLow AND :priceHigh "
+ "AND p.averageRating >= :averageRating "
+ "AND p.archived = :archived "
+ "AND ((category.name IN :selectedCategories) "
+ "OR (:amountOfSelectedCategories = 0 AND category IN (SELECT c FROM Category c))) "
+ "GROUP BY p "
+ "HAVING SIZE(p.categories) >= :amountOfSelectedCategories"
)
Page<Product> findAllBySearchModel(
Pageable pageable,
#Param("searchRequest") String searchRequest,
#Param("description") String description,
#Param("priceLow") BigDecimal priceLow,
#Param("priceHigh") BigDecimal priceHigh,
#Param("averageRating") double averageRating,
#Param("archived") boolean archived,
#Param("selectedCategories") List<String> selectedCategories,
#Param("amountOfSelectedCategories") int amountOfSelectedCategories
);

Related

HQL QuerySyntaxException: unexpected AST node

Searched and found a lot of questions about this but nothing for my particular case. I am getting an error on my HQL query, here is the code:
final Query query = session.createQuery(
" SELECT DISTINCT e " +
" FROM Employee e" +
" INNER JOIN Requisition r on r.supervisor = e.id " +
" WHERE r.status = 'Open' " +
" AND r.isEvergreen = false " +
" AND r.isConfidential = false " +
" AND r.employmentType != 'Intern (Fixed Term)' " +
" AND (" +
" CASE WHEN :searchString IS NOT NULL THEN (CONCAT(e.firstName, ' ', e.lastName) LIKE CONCAT('%', TRIM(:searchString), '%')) END)" +
" ORDER BY e.firstName, e.lastName")
.setParameter("searchString", searchString);
And here's the error log:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: CASE near line 1, column 329 [ SELECT DISTINCT e FROM <Insert the rest of the query>
The query works if I remove the CASE WHEN statement in the final AND and the setParameter. So that means something is wrong with the final AND (...) and/or the newly introduced parameter.
I am new to Hibernate and am struggling with this since the error message isn't super helpful. Any ideas?
The case you have does not complete the condition.
You can simplify the case as follows :
(coalesce(:searchString,1,0) =1 OR e.firstName||' '|| e.lastName LIKE '%'||:searchString||'%')
The first coalesce will check if searchstring is null , if it is will return 1 and 0 if it is not.
If it returns 1 , the expression after OR will not get evaluated.
If first expression return 0 , the expression after OR will be evaluated
This will fulfill your usecase to apply searchString filter only when it is not null.

Java convert Postgres query into JPA Criteria builder

I have this sql query which I am using native sql to process currently and I need to transform it to use the JPA criteria builder so I can dynamically build up the where conditions. I am currently semi building the conditions dynamically in a janky way in sql (AND (case when 0 in :#{#filter.modelIds} then true else model_id in :#{#filter.modelIds} end)
Also, Im not sure what the best practices are and if I should just leave the code I currently have or move it over to Criteria builder. A lot of articles I read have said not to use criteria builder for advance quires. For me everything works but some people expressed concerns over the maintainability of the code. To me I like looking at sql versus the criteria builder just confuses me :)
Another blocker for me is I'm using the Postgres function generate_series to create all the dates in a date range so that way I can have empty values for dates with no data. I was not sure how to translate this over to the criteria builder I figured out how to use the date trunc function Expression<Date> view_date = builder.function("date_trunc", Date.class, builder.literal("day"), root.get("acquisitionDate")); The only other thought I had was to just execute the sub query and the use java to build up the date array and map my results to it
SQL:
select date, COALESCE(views, 0) as count, model_id
from generate_series(date '2020-05-9',date '2020-05-18',interval '1 day')as t(date)
left join (
select date_trunc('day',acquisition_date) as view_date, count(acquisition_date) as views, model_id
from view
where acquisition_date between '2020-05-9' and '2020-06-19'
group by model_id, view_date
order by view_date asc
) as v on v.view_date = date
order by date asc;
Repository:
#Query(
value = "select date, COALESCE(views, 0) as count, d.model_id as itemId " +
"from generate_series(date (:#{#filter.startDate}),date (:#{#filter.endDate}), CAST('1'||' '||:#{#filter.getInterval()} AS Interval))as t(date)" +
"left join (" +
"select date_trunc((:#{#filter.getInterval()}),acquisition_date) as view_date, count(acquisition_date) as views, model_id " +
"from view " +
"WHERE acquisition_date between (:#{#filter.startDate}) and (:#{#filter.endDate})" +
"AND (case when 0 in :#{#filter.modelIds} then true else model_id in :#{#filter.modelIds} end)" +
"AND (case when '0' in :#{#filter.imageIds} then true else image_id in :#{#filter.imageIds} end) " +
"AND (case when 0 in :#{#filter.objectIds} then true else object_type_id && array[(:#{#filter.getObjectArray()})] end)" +
"group by model_id, view_date " +
"order by view_date asc" +
") as v on v.view_date = date_trunc((:#{#filter.getInterval()}), date) " +
"order by date asc",
nativeQuery = true
)
List<ItemDateCountProjection> getModelViewsByDate(#Param("filter") ViewFilter filter);
Projection
public interface ItemDateCountProjection {
String getItemId();
Integer getCount();
Date getDate();
}

JPA repository findBySOMETHING, could not extract result

I'm using JPA repository for some toy project, I want to get List of object SOMETHING, but result is could not extract ResultSet; SQL[n/a].
This is my object (nothing is important, just focus on lob plz)
{
...
private Long id
#Lob
#Column(columnDefinition = "text")
private String content;
...
}
Then, I use repository to findByContentLike("CONTENT"), then result is failed, the reason is that cannot extract result.
why this happened? even i set on application.properties like spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
there anyone know about this error? please bring me to the light.
If you need auto parameter bound wrapped in %(wildcard) use
findByContentContaining("Content")
Or you need to manually add %(wildcard) in the string
findByContentLike("%Content%")
JPA-methodqueries require a special syntax. Most commonly they are build up as: findBy + a field of your entity. In your case, the like is redundant.
See this reference to the docs for examples.
As complexity increases, you might want to write your own queries, using JPQL. A small example:
#Query("SELECT p FROM Product p "
+ "LEFT JOIN p.categories category "
+ "WHERE UPPER(p.name) LIKE UPPER(CONCAT('%', COALESCE(:searchRequest, ''), '%')) "
+ "AND UPPER(p.description) LIKE UPPER(CONCAT('%', COALESCE(:description, ''), '%')) "
+ "AND p.price BETWEEN :priceLow AND :priceHigh "
+ "AND p.averageRating >= :averageRating "
+ "AND p.archived = :archived "
+ "AND ((category.name IN :selectedCategories) "
+ "OR (:amountOfSelectedCategories = 0 AND category IN (SELECT c FROM Category c))) "
+ "GROUP BY p "
+ "HAVING SIZE(p.categories) >= :amountOfSelectedCategories"
)
Page<Product> findAllBySearchModel(
Pageable pageable,
#Param("searchRequest") String searchRequest,
#Param("description") String description,
#Param("priceLow") BigDecimal priceLow,
#Param("priceHigh") BigDecimal priceHigh,
#Param("averageRating") double averageRating,
#Param("archived") boolean archived,
#Param("selectedCategories") List<String> selectedCategories,
#Param("amountOfSelectedCategories") int amountOfSelectedCategories
);
Don't forget to mark your entity class with #Entity and to have your repository extend JpaRepository<MyEntityClass, Long> where the Long corresponds with your entity's #Id field.

LIKE COALESCE in Spring JPA does not work

So my problem is the following:
I have a table I want a filter to apply to. This filter should call a query which finds based on the given information the reports.
This is how my query looks:
#Query("SELECT r FROM Report r WHERE r.importanceLevel = COALESCE(importance,'%')" +
"AND r.source = COALESCE(source,'%')" +
"AND r.resolvedStatus = COALESCE(resolvedStatus,'%')" +
"AND r.header LIKE + '%' COALESCE(query,'%') + '%'")
List<Report> getReportsByAppliedFilter(#Param("importance") int importance, #Param("source") String source,
#Param("resolvedStatus") int resolvedStatus, #Param("query") String query);
Problem is: IntelliJ does not like the following:
LIKE + '%' COALESCE(query,'%') + '%'
Error: expected, got +
Do you have any idea how to solve this otherwise?
Yeah, time to go to bed. You dont use + for concat , you use concat():
#Query(value = "SELECT r FROM Report r WHERE r.importanceLevel = COALESCE(importance,'%')" +
"AND r.source = COALESCE(source,'%')" +
"AND r.resolvedStatus = COALESCE(resolvedStatus,'%')" +
"AND r.header LIKE CONCAT('%', COALESCE(query,'%'), '%')")
If your column name is request_status and table name is connections then use COALESCE like
#Query(value = "SELECT connections.id, COALESCE(connections.request_status,'') as request_status.... ", nativeQuery = true)
List<ZXYType> xysfunction();
Here if request_status is null then it will be replaced by an empty string.

Spring Data (REST) & #Query: optional list as param

I'm having the following function in one of my repositories:
#RestResource(path = "filter", rel = "filter")
#Query("SELECT t "
+ "FROM Trip t "
+ "WHERE "
+ "(:from IS NULL OR t.startTs >= :from) "
+ "AND (:categories IS NULL OR t.category IN :categories) ")
Page<Trip> filter(
#Param("from") Instant from,
#Param("categories") List<Category> categories,
Pageable pageable);
The Category is an enum which is stored as:
#Enumerated(EnumType.STRING)
in the Trips table.
When I'm doing my HTTP request with exactly one category I'm getting the correct results. Same behaviour when doing a request without categories key.
htt*://localhost/filter?categories=PRIVATE ==> ok
htt*://localhost/filter ==> ok
When using more than one category:
htt*://localhost/filter?categories=PRIVATE,BUSINESS
I'm getting the following exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST
node: {vector} [select count(t) FROM foo.bar.services.trips.model.Trip
t WHERE (:from IS NULL OR t.startTs >= :from) AND (:categories_0_,
:categories_1_ IS NULL OR t.category IN (:categories_0_,
:categories_1_)) ]
Anybody have an idea what I'm doing wrong here?
Try one of the following:
1) Try to enclose the statements involving the list in parentheses:
#Query("SELECT t "
+ "FROM Trip t "
+ "WHERE "
+ "(:from IS NULL OR t.startTs >= :from) "
+ "AND ((:categories IS NULL) OR (t.category IN :categories)) ")
2) Enclose the :categories in parentheses here
t.category IN (:categories)

Categories

Resources