how to pass sql query condition dynamically to #query as param - java

Is it possible to add dynamic sql condition to query annotations
Say when n= : name
n != : name
n like "%:name%"
The formation of condition based on the user input
public interface PersonRepository extends CrudRepository<Person, Long> {
#Query("select p from Person AS p"
+ " ,Name AS n"
+ " where p.forename = n.forename "
+ " and p.surname = n.surname"
+ " and n = :name")
Set<Person>findByName(#Param("name") Name name);
}
instead of writing "and n = :name " i want form sql condition dynamically when user select = , or != or like
"and n != :name "
"and n like '%:name%'"
seems like Filtering option

I think the most simple way for Spring Data Jpa would be using specifications based on JPA Criteria API.

Related

Query String with native query and ordered parameter, sql doesn't work

I have the following code
#Query(nativeQuery = true, value = "select e.* from event e"
+ " join league l on (l.id = e.league_id)"
+ " join sport s on (l.sport_id = s.id)"
+ " join team t1 on (t1.id = e.team_one_id)"
+ " join team t2 on (t2.id = e.team_two_id)"
+ " join country c on (c.id = l.country_id)"
+ " where l.name LIKE %?1%")
Page<Event> getAllEventsFiltered(final PageRequest of, final String filter);
If execute this SQL into database I receive a lot of results but when is executed from java I receive no one result in the same SQL.
I already tried:
where l.name LIKE %?#{escape([1])} escape ?#{escapeCharacter()}
but just works to begins and I needs for both begin and end.
JDBC parameters can only be included in very specific places in a SQL statement. They are not replaced as strings in the SQL statement but they are applied. The specific valid places change from database to database, and also depend on the JDBC driver variant/version.
The general rule is that a parameter can be applied where a single value would be present. String parameters should not be enclosed in single quotes as a VARCHAR would be.
One option to make it compliant, is to place the parameter isolated from other text, for example by using the CONCAT() function. Your query could be rephrased as:
#Query(nativeQuery = true, value = "select e.* from event e"
+ " join league l on (l.id = e.league_id)"
+ " join sport s on (l.sport_id = s.id)"
+ " join team t1 on (t1.id = e.team_one_id)"
+ " join team t2 on (t2.id = e.team_two_id)"
+ " join country c on (c.id = l.country_id)"
+ " where l.name LIKE concat('%', ?1, '%')") // change here
Nevertheless, the specific syntax change can be different depending on the database you are using (that you haven't mentioned).

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.

Filter rows in DataSet using JPA/Hibernate

I have the following code which is used to retrieve data from multiple tables (using joins) and then mapping every row into a DTOList but I also need to apply filters based on user preferences: per table1.name or table2.name, table3, etc.
So I just want to know what would be the best way to do it in terms of performance and best practices;
retrieving all rows and then apply the filters with lambdas (easier)
change the query to a dynamic query with Criteria or something else?
Any other solution=?
#Repository
public class ArchiveRepository {
#Autowired
EntityManager em;
String queryStr = "select wsr.id as sampleid, s.id as slideid, tb.name as batchname, k.lot_number as kitlot, " +
" 'STRING' as slidetype, tb.worklist_name as worklist, wsr.final_call as results, " +
" wa.final_pattern_ids as patterns, 'edited/yesno' as edited, wsr.last_modified_by as user, wsr.last_modified_date as time " +
" from slide s " +
" left join table2 tb on s.test_batch_id = tb.id " +
" left join table3 k on tb.kit_lot_id = k.id " +
" left join table4 w on s.id = w.slide_id " +
" left join tabl5 pw on pw.well_id = w.id " +
" left join tabl6 cw on cw.well_id = w.id " +
" left join tabl7 wsr on wsr.patient_well_sample_id = pw.id or wsr.control_sample_id = cw.id " +
" left join (select * from *** (other subselect)) wa on wa.well_sample_id = wsr.**id or wa.well_sample_id = wsr.**id " +
"where tb.state = 'STATENEEDED'";
public ArchiveDataListDTO getArchiveData(){
Query query = em.createNativeQuery(queryStr);
ArchiveDataListDTO archiveDataListDTO = new ArchiveDataListDTO();
List<Object[]> resultL = (List<Object[]>)query.getResultList();
for( Object[] o : resultL){
archiveDataListDTO.addArchiveDataRow(
new ArchiveDataDTO((String)o[0], String.valueOf(o[1]), (String) o[2], (String) o[3], (String) o[4], (String) o[5],
(String) o[6], (String) o[7], (String) o[8], (String) o[9], (String) o[10]));
}
return archiveDataListDTO;
}
}
**
note I struggled some with the code cause I wanted to apply #sqlresultsetmapping to avoid manual results mapping but it just didn´t work, most of the examples out there are when you have an entity in the DB but in this case I retrieve from many tables.**
Thanks so much
2 .- change the query to a dynamic query with Criteria or something else?
I ended up creating the query on the fly; depending on the filters I get from UI i assemble the query with Java and send it to DB, it´s easier since this required many tables...

Spring JPA filter optional criteria in Query method

I want to filter out data from a database with few criteria (let's assume it is 8).
And below query method do this in a good way. But in fact, this criterias passed to the query method can be null (it means that should not be included to select query).
How I should handle this situation?
I really don't want to make n-methods to handle each case - it is not a good way.
#Query("SELECT NEW api.model.GeneralAnnouncementInfo(" +
"an.id, an.title, po.price, SUBSTRING(an.description, 1, 100), an.provider, an.creationDate, an.url, l.lessorType, concat(loc.city, ' ', loc.district)) " +
"FROM Announcement as an " +
"LEFT JOIN an.priceOffer as po " +
"LEFT JOIN an.lessor as l " +
"LEFT JOIN an.location as loc " +
"LEFT JOIN an.propertyData as pd " +
"WHERE l.lessorType = (:lessor) " +
"AND pd.roomNumber = (:rooms) " +
"AND pd.bathroomNumber = (:baths) " +
"AND pd.parkingAvailability = (:parking) " +
"AND pd.isSmokingAllowed = (:smokers) " +
"AND pd.isPetFriendly = (:pets) " +
"AND pd.area = (:realPrice) " +
"AND po.price = (:area) ")
Page<GeneralAnnouncementInfo> getAnnouncementsBySearchCriteria(Pageable pageable,
String lessor,
String rooms,
String baths,
String parking,
String smokers,
String pets,
String realPrice,
String area
);
I would recommend switching to the JPA Criteria API. It will give you the extra flexibility you are seeking (and which JPQL seems to be maxing out for your case). You can build your queries programmatically without any limitations and the best thing is that they get compiled; which means that no typos will survive (which are a nightmare to track in JPQL queries). Additionally you may want to use JPA metamodel classes; which add more robustness to your queries. At the end, your repository method would look something like this:
private EntityManager em;
private Page<GeneralAnnouncementInfo> getAnnouncementsBySearchCriteria(QueryParameters qParams) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SampleEntity> criteria = cb.createQuery(GeneralAnnouncementInfo.class);
Root<GeneralAnnouncementInfo> root = criteria.from(GeneralAnnouncementInfo.class);
// Programmatically build query details (conditions, joins, aggregations, translation, etc)
// ...
// ...
// ...
return em.createQuery(criteria).getResultList();
}

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.

Categories

Resources