I am a newbie to Spring and java, I have a scenario, where i like to query like below:
when i have a po.id value, i can search like this below:
form service :
prescriptionOrderRepository.searchPharmacyOrders(args);
I am writing my spring query like this:
#Query(value = "select po from PrescriptionOrder po WHERE po.pharmacyId = :pharmacyId "
+ "AND po.id = :idValue AND po.active = :active ORDER BY po.createdAt DESC")
Page<PrescriptionOrder> searchPharmacyOrders(#Param("pharmacyId") Long pharmacyId,
#Param("idValue") Long idValue, Pageable pageRequest, #Param("active") Boolean active);
Suppose if i have to requirement, po.id is an optional field means, how can write query for that.
I always expect the params, they're either null by default, or I get a value and it has to match. So for a parameter :idValue your query has
... AND (po.id = :idValue OR :idValue is null) ...
When e.g. you come from a Controller class, using GET variables, you can always use them as default null, or you're getting a value and it has to match.
In your example, that query in total...
WHERE (po.pharmacyId = :pharmacyId AND po.id = :idValue AND po.active = :active
Changes to:
WHERE ((po.pharmacyId = :pharmacyId OR :pharmacyId is null) AND (po.id = :idValue OR :idValue is null) AND (po.active = :active OR :active is null)
Related
I am trying to get details of Properties details from database using JPQL, Hear I am writing where condition like (properties.IsDeleted <> 'Y' or properties.IsDeleted IS NULL)
but, in JPQL query it is not getting 'Y', but, it is was showing like '?' symbol. this is the problem I am getting. please help me from this issue.
the below code is showing query like:-
select properties0_.property_id as col_0_0_,
properties0_.property_type as col_1_0_, properties0_.property_name as
col_2_0_, properties0_.property_area as col_3_0_,
properties0_.property_city as col_4_0_, properties0_.no_of_rooms as
col_5_0_ from iot_property properties0_ where
(properties0_.is_deleted<>? or properties0_.is_deleted is null) and
properties0_.property_id=6
In the above query in bold mark shows properties0_.is_deleted<>? ,but what I want is properties0_.is_deleted<>Y
why that "Y" is not assigned to that query. that I am not understanding.
will you please help me to solve this issue.
Thanks
CriteriaBuilder deviceBuilder = propertySession.getCriteriaBuilder();
CriteriaQuery<Object[]> userCriteriaQuery = deviceBuilder.createQuery(Object[].class);
Root<Properties> propertyRoot = userCriteriaQuery.from(Properties.class);
Path<Object> pathPropertyId = propertyRoot.get("propertyId");
Path<Object> pathpropertyType = propertyRoot.get("propertyType");
Path<Object> pathpropertyName = propertyRoot.get("propertyName");
Path<Object> pathpropertyArea = propertyRoot.get("propertyArea");
Path<Object> pathpropertyCity = propertyRoot.get("propertyCity");
Path<Object> pathnumberOfRooms = propertyRoot.get("numberOfRooms");
userCriteriaQuery.multiselect(pathPropertyId, pathpropertyType, pathpropertyName, pathpropertyArea,
pathpropertyCity, pathnumberOfRooms);
Predicate userRestriction = deviceBuilder.or(deviceBuilder.notEqual(propertyRoot.get("isDelete"), "Y"),
deviceBuilder.isNull(propertyRoot.get("isDelete")));
Predicate userRestriction2 = deviceBuilder
.and(deviceBuilder.equal(propertyRoot.get("propertyId"), propertyId));
userCriteriaQuery.where(deviceBuilder.and(userRestriction, userRestriction2));
Query<Object[]> deviceQuery = propertySession.createQuery(userCriteriaQuery);
List<Object[]> resultList =deviceQuery.getResultList();
for(Object[] objects : resultList) {
Integer dbPropertyId = (Integer) objects[0];
String dbPropertyType = (String) objects[1];
String dbpropertyName = (String) objects[2];
String dbpropertyArea = (String) objects[3];
String dbpropertyCity = (String) objects[4];
Integer dbNoOfRooms = (Integer) objects[5];
System.out.println(dbPropertyId);
System.out.println(dbPropertyType);
System.out.println(dbpropertyName);
System.out.println(dbpropertyArea);
System.out.println(dbpropertyCity);
System.out.println(dbNoOfRooms);
}
There is no such thing as "the final JPQL that ultimately gets translated to the final SQL with inserted paramerters". How a JPA implementation generates the SQL is down to it, and parameters, in general, will never be substituted into any String. SQL has generated from expression trees etc, not a String. This is a criteria query so for parameters it will show "?" on the console.
If you want param values inserting in then do it yourself since it only makes sense to you
Currently I am doing it like this:
List<Table1Entity> findAllMatchingEntities(Table1Entity table1Entity) {
String queryString = "SELECT table1.* FROM table1 "
+ "JOIN table2 t2 ON table1.id=t2.table1_id";
if (table1Entity.getName() != null) {
queryString +=" where name like ?";
}
Query query = em.createNativeQuery(queryString, Table1Entity.class);
if (table1Entity.getName() != null) {
query.setParameter(1, table1Entity.getName())
}
return query.getResultedList();
}
If I want to check more parameters in this join this will quickly turn into a lot of if statements and it would be really complicated to set parameters correctly.
I know I can check parameters with criteria Builder API like this:
if(table1Entity.getName() != null) {
table1EntitySpecification = (root, query, criteriaBuilder)
-> criteriaBuilder.like(
criteriaBuilder.lower(root
.get("name")),
("%" + table1Entity.getName() + "%")
.toLowerCase());;
}
and after that get them all with:
findAll(table1EntitySpecification) with findAll from simpleJPARepository. Now I can chain them together with .or or .and etc. and avoid setting the parameter and checking for null second time.
But how do I do join with criteria APi?
I know I can have in my #Repository something like this:
#Query(value = "SELECT table1.* FROM table1 JOIN table2 t2 ON table1.id=t2.table1_id", nativeQuery = true)
List<Table1Entity> findAllMatchingEntities(Table1Entity table1Entity);
But since name is optional (can be null) I can't just leave it in #Query.
What is the best solution here to avoid using native query and in case of having to check many parameters to avoid using if statements?
I don't know if I fully get your question, but regarding the possibility of nulls, and using the CRUD repository, you can always do a null check before like:
#Query(value = "SELECT table1.* FROM table1 JOIN table2 t2 ON table1.id=t2.table1_id WHERE table1.id is not null", nativeQuery = true)
List<Table1Entity> findAllMatchingEntities(Table1Entity table1Entity);
Depending on what you are trying to achieve, you can always compose the query with similar checks like (not related to your code):
#Query("SELECT c FROM Certificate c WHERE (:id is null or upper(c.id) = :id) "
+ "and (:name is null or upper(c.name) = :name)")
List<Table1> findStuff(#Param("id") String id,
#Param("name") String name);
I have an jpql query inside a JpaRepository like this:
#Query("select l from LogEntity l where l.codePackage = :codePackage and l.codeFile = :codeFile order by l.id desc")
public Page<LogEntity> findSimilarAngularLog (#Param("codePackage") String codePackage, #Param("codeFile") String codeFile, Pageable pageRequest);
The variable codePackage and codeFile can be NULL. But hibernate is always making something like
... where l.codePackage=? and l.codeFile=? ...
out of it. So if one or both of them are NULL, then there is l.codeFile=NULL and not l.codeFile IS NULL. And then he does not find anything at all.
If I copy the hibernate generated sql string to my MySQL console and change the =NULL to IS NULL, he will find everything.
So how do I change the behavior of hibernate jpa, so that in my #Query String the NULL will be treated correctly.
thanks a lot and greetings
You can use the below query for that:
#Query("select l from LogEntity l where ((:codePackage is null and l.codePackage is null) or l.codePackage = :codePackage) and ((:codeFile is null and l.codeFile is null) or l.codeFile = :codeFile) order by l.id desc")
But wouldn't that be a good idea to make hql through the logic rather than using it like the named queries?
A better logic would be to use an if condition, like,
if(codePackage == null) {
query += " l.codePackage is null ";
}
else {
query += " l.codePackage = :codePackage ";
}
***code***
//query execution code
WHERE ((:param is null and t.field is null) or t.field = :param)
#Query("select l from LogEntity l where ((:codePackage is null and l.codePackage is null) or l.codePackage = :codePackage ) and ((:codeFile is null and l.codeFile is null) or l.codeFile = :codeFile ) order by l.id desc")
I have the following DAO method:
public String getSomeTable(final String param1) {
String sqlString = "select * from table where name ilike ?";
Query query = this.getEntityManager().createNativeQuery(sqlString);
query.setParameter(1, "%param1%");
}
If param1 is null or empty then I want to select all entries from the table. What is the correct way to do this? I am currently using the following:
public String getSomeTable(final String param1) {
String sqlString = "select * from table where name = ?";
Query query = this.getEntityManager().createNativeQuery(sqlString);
if(param1 == null)
query.setParameter(1, "%%");
else
query.setParameter(1, "%param1%");
}
But this is not scalable. I have datatypes like integer, date, etc. I want to know if there is a way to skip checking for that parameter if it is null.
I was planning to use COALESCE(?, CASE WHEN ? = '' THEN '%%' ELSE '%?%') but I think ? can be used only once for a particular parameter. The next one > I write is linked to second param.
On SQL Server, I use something like this, perhaps you can translate it to postgres:
DECLARE #variable INT = NULL;
SELECT *
FROM sysobjects
WHERE
(1 = CASE WHEN #variable IS NULL THEN 1 ELSE 2 END)
OR
(id LIKE #variable);
am trying to form a query based on parameters, if the parameters for WHERE clause is null or not. it seems to be a huge code if i do this on if and else. Is there any other smart way to this??
example :
String query = "SELECT CUSTOMER_NAME FROM CUSTOMER_TABLE WHERE ";
if(cust_id !=null && !(cust_id.trim().equalsIgnoreCase("")))
{
query = query + "cust_id='"+cust_id+"'";
}
else
{
}
checking all the columns like this, the code is looking like a mess, please let me know if there is an other way to do this
adding to the above question :
I also have the parameters for like operator
example
if(strCustName!=null)
{
String query = "SELECT * FROM CUSTOMER WHERE CUSTOMER_NAME LIKE '"+strCustName+"';
}
You can use NamedParameterJDBCTemplate
And your query could be
... WHERE (cust_id=:custIdParam OR :custIdParam is null)
AND (another_column=:another_param OR :another_param is null)
UPDATE:
String sqlstr = "select * from the_table where lastname like :lastname or :lastname is null"
NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(datasource);
Map namedParameters = new HashMap();
namedParameters.put("lastname", "%test%");
SqlRowSet result = jt.queryForRowSet( sqlstr ,namedParameters );
from the link