Java hibernate query issues with order by clause - java

Hi I am using hibernate query and trying to get results order by the id, but the getResultList function is always returning the result in ascending order even though my query has an order by clause of deviceActivityLogId.
Here is my function
public List<DeviceActivityLog> getActivityLogForSysActivityId(int userDeviceRelId,int sysActivityId, int parentId, boolean deleteFlag) {
String query = "select d from DeviceActivityLog d WHERE d.userDeviceRelId = :userDeviceRelId and d.deleteFlag = :deleteFlag";
if (sysActivityId > 0) {
query += " and d.sysActivityId = :sysActivityId";
}
if (parentId >= 0) {
query += " and d.isParent =:parentId";
}
TypedQuery<DeviceActivityLog> deviceQuery = entityManager.createQuery(query, DeviceActivityLog.class);
deviceQuery.setParameter("userDeviceRelId", new UserDeviceRel(userDeviceRelId));
deviceQuery.setParameter("deleteFlag", deleteFlag);
if (sysActivityId > 0) {
deviceQuery.setParameter("sysActivityId", new SysActivity(sysActivityId));
}
if (parentId >= 0) {
deviceQuery.setParameter("parentId", parentId);
}
query+=" order by d.deviceActivityLogId desc";
System.out.println("QUERY: "+query);
return deviceQuery.getResultList();
}
Can anyone provide a soultion how to get the result list in descending order?

You're assigning a new value to your query String variable AFTER the TypedQuery object has been created from the PREVIOUS value of the query variable.
This is basically equivalent to
String message = "Hello";
System.out.println(message);
message += " World";
That will obviously print Hello, not Hello World.
It would print Hello World if the code was
String message = "Hello";
message += " World";
System.out.println(message);

You change the query string after building the query object.
put your statement
TypedQuery<DeviceActivityLog> deviceQuery = entityManager.createQuery(query, DeviceActivityLog.class);
at the end (just before return deviceQuery.getResultList();) and you should be fine.

Related

Dynamically build SQL where clause based on presence of attributes in DTO

I have a screen where users can search a table based on 1 or more of its columns. I am passing the columns the users would like to filter by as a DTO to the backend.
There I am building a SQL to query by checking for the presence of these fields in the DTO...
Object transactionSearch (TransactionSearchDTO dto ){
StringBuilder transactionQuery = new StringBuilder()
transactionQuery.append("SELECT id, delivery_date, order_date, customer_name FROM transaction where 1=1 ")
if (dto.order_id) {
transactionQuery.append("and order_id = ${dto.order_id}")
}
if (delivery_date) {
transactionQuery.append("and order_id = ${delivery_date}")
}
if (customer_name) {
transactionQuery.append("and order_id = ${customer_name}")
}
}
What I am ending up with is a ton of if statements for each column.
Is there a way to achieve this without having an if block per filter?
I found some ideas here but I need a solution in Groovy or Java.
i suggest to use GString instead of StringBuilder to pass parameters correctly to groovy.sql.Sql
class DTO{
int id
String name
Date created
}
def a = new DTO(id:123, created:new Date())
GString f(DTO a){
GString q = GString.EMPTY + 'select ' + a.getProperties().collect{k,v-> k}.join(',')+' from T'
a.getProperties().each{k,v->
if(k!='class' && v!=null){
q = q + ( q.getValueCount()==0 ? ' WHERE ' : ' AND ' )
q = q + k + " = ${v}"
}
}
return q
}
def s = f(a)
println s
println s.getValues()
println s.getStrings()

How to execute Pre-build Query in Java Spring

I need to execute pre-build SQL query in java spring, I created query as follows,
String query = "select * from device where";
if (status != null) {
query += " status = "+status;
}
if (cinema != "") {
query += " and cinema_code = \'"+cinema+"\'";
}
if (content_profile != "") {
query += " and content_profile = \'"+content_profile+"\'";
}
if (mac != "") {
query += " and mac = \'"+mac+"\'";
}
Build query:
select *
from device
where status = 2
and cinema_code = 'AL10'
and content_profile = 'signage'
You can use Spring Data JPA Specifications for dynamic queries.
Give a look here:
https://www.baeldung.com/rest-api-search-language-spring-data-specifications
If you don't want JPA you can use Spring JDBC
Execute query:
String query = "select * from device where status = 2 and cinema_code = 'AL10' and content_profile = 'signage'";
List<Device> devices = jdbcTemplate.queryForObject(
query, new Object[] { }, new DeviceRowMapper());
Mapper can look like this:
public class DeviceRowMapper implements RowMapper<Device> {
#Override
public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
Device device = new Device();
device.setId(rs.getInt("ID"));
...
return device;
}
}
How to config the connection in providing url
However as it was mentioned in comments. It is better not to concatenate string parameters.
Your query building can be done in that way.
String query = "select * from device where";
List parameters = new ArrayList();
boolean wasParameter = false;
if(status != null) {
query += " status = ? ";
parameters.add(status);
wasParameter = true;
}
if(cinema != "") {
query += (wasParameter ? " and ": "") +" cinema_code = ? ";
parameters.add(cinema);
wasParameter = true;
}
if(content_profile != "") {
query += (wasParameter ? " and ": "") +" content_profile = ? ";
parameters.add(content_profile);
wasParameter = true;
}
if(mac != "") {
query += (wasParameter ? " and ": "") +" mac = ? ";
parameters.add(mac);
}
Object[] array = parameters.toArray(new Object[0]);
And execute query:
List<Device> devices = jdbcTemplate.queryForObject(
query, array, new DeviceRowMapper());
Assuming that you have configured the Spring datasource you can execute a Spring native query using:
EntityManager em = emf.createEntityManager();
List<Object> results = em.createNativeQuery(query);
You should also update your query, because you can easily get a SQLException when status is null. If it happens you will have an invalid query:
select *
from device
where and cinema_code = 'AL10' and content_profile = 'signage'
Try to use this initial query:
"select * from device where 1=1 "
Using the above, the query will be correct no matter if the first if is executed or no ifs executed at all.

JDBC dynamic query, only put value to string if not -1

I have a problem with JDBC and java.
I have a Query like this:
String updateSql = "UPDATE league SET season=?, playedMatches=?, percentHomeWins=?, percentDraws=?, percentAwayWins=?, averageGoalsPerGame=?, averageGoalsHomePerGame=?, averageGoalsAwayPerGame=?, percentOverOne=?, percentOverTwo=?, percentOverThree=?, percentBothTeamsScored=?, scoredGoalsTotal=? " + whereClause + " and country='" + l.getCountry() + "'";
all values after "season" can either be a number >= 0 or -1. -1 means, that there is no value. the values come from a class that holds data (like an object model).
I want only the values in my query, which are >= 0. The other one should not be in the query, because they replace data in the database, which they should not.
Can anyone help me archiving this?
Use a StringBuilder to dynamically build the SQL statement, e.g.
StringBuilder sql = new StringBuilder("UPDATE league SET season=?");
List<Integer> numValues = new ArrayList<>();
if (l.getPlayedMatches() != -1) {
sql.append(", playedMatches=?");
numValues.add(l.getPlayedMatches());
}
if (l.getPercentHomeWins() != -1) {
sql.append(", percentHomeWins=?");
numValues.add(l.getPercentHomeWins());
}
// ... more code ...
sql.append(whereClause)
.append(" and country=?");
try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) {
int paramIdx = 0;
stmt.setInt(++paramIdx, l.getSeason());
for (Integer numValue : numValues)
stmt.setInt(++paramIdx, numValue);
stmt.setString(++paramIdx, l.getCountry());
stmt.executeUpdate();
}

MYSQL+Hibernate, Query cannot be created

Can someone help me to have a look at what is wrong with my query?
Java code :
public boolean fValidLogin(String fUsername, String fPassword) {
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session session = sf.openSession();
String query = "SELECT fusername,fpassword FROM flogin WHERE fusername=" + fUsername + " AND fpassword=" + fPassword + "";
Query DBquery = session.createQuery(query);
for (Iterator it = DBquery.iterate(); it.hasNext();) {
it.next();
count++;
}
System.out.println("Total rows: " + count);
if (count == 1) {
return true;
} else {
return false;
}
}
MYSQL Code:
SELECT fusername,fpassword FROM flogin WHERE fusername="SAS" AND fpassword="Sas123"
Try this first:
"SELECT fusername,fpassword FROM flogin WHERE fusername=\"" + fUsername + "\" AND fpassword=\"" +fPassword +"\""
By the way you are tring to use a native query. Maybe you should consider to use "createNativeQuery" instead of "createQuery"
Your query is a victim of an SQL Injection, it can also cause syntax error, instead you have to use setParameter with a JPQL query :
String query = "SELECT f FROM flogin f WHERE f.fusername = ? AND f.fpassword = ?";
Query dBquery = session.createQuery(query);
dBquery.setParameter(0, fUsername);//set username variable
dBquery.setParameter(1, fPassword);//set password variable
To get the nbr of result you can just call Query::list()
int count = dBquery.list().size();
Or just :
return dBquery.list().size() == 1;
The real problem in your query is that the String should be between two quotes (but i don't advice with solution)
fusername='" + fUsername + "'
//--------^_________________^
Note: Your query is not a JPQL Query, it seems a native query, if that you have to use session.createNativeQuery(query);.

how to generate sql query dynamically having specific colums

I have several tables. I have a query also. My problem is to generate the SQL query dynamically using Java.
I have the following fields in a separate table:
Collumn name status
po_number, Y
unit_cost, Y
placed_date , Y
date_closed, Y
scheduled_arrival_date Y
date_closed Y
order_quantity Y
roll_number N
product_sku N
product_category_name N
rec_vendor_quantity Y
vendor_name Y
et_conversion_unit_quantity Y
from which i have to generate a query when the status is Y, the problem here is some time the above columns
The following query is the out put of the above :
here i have inculded all the columns but i have to exculde the column which has the status of N, please help me to construt the query using java.
select
pi.po_number,poi.unit_cost,pi.placed_date CreateDate,
case when isnull(pi.date_closed) then pi.scheduled_arrival_date
else pi.date_closed end as ReceviedDate,
poi.order_quantity,poi.roll_number,p.product_sku product_name,
pc.product_category_name,poi.rec_vendor_quantity,pv.vendor_name,p.et_conversion_unit_quantity,pi.note
from
purchase_order as pi,
purchase_order_inventory as poi,
product_vendors as pv,
products AS p,
product_categories AS pc
where
pi.purchase_order_id=poi.purchase_order_id and
pc.product_category_id=p.product_category_id and
poi.product_id = p.product_id and
poi.product_category_id=pc.product_category_id and
pi.vendor_id=pv.product_vendor_id and
( ( pi.date_closed >= '2012-01-01' and pi.date_closed <='2012-09-05 23:59:59' )
or ( pi.scheduled_arrival_date >= '2012-01-01' and pi.scheduled_arrival_date <='2012-09-05 23:59:59') ) and
pi.po_type=0
and pi.status_id = 0 and poi.transaction_type = 0
order by pi.po_number
UPDATE :
QUERY : STEP 1:
SELECT rcm.id,rcm.tablename,rcm.columnname,rcm.size,rcm.displayorder,rcm.isactive FROM report_customise_master rcm where rcm.tablename !='employee' and rcm.isactive='Y' order by rcm.displayorder;
STEP 2 :
Java method to construct the query :
public Map getComplexReportQuery() {
String query = "SELECT rcm.id,rcm.tablename,rcm.columnname,rcm.size,rcm.displayorder,rcm.isactive FROM report_customise_master rcm where rcm.tablename !='employee' and rcm.isactive='Y' order by rcm.displayorder;";
String tableName = "", from = "", select = "";
StringBuffer sb = new StringBuffer();
Map<String, List<String>> resultsMap = new LinkedHashMap<String, List<String>>();
Map<String, String> displayOrderMap = new LinkedHashMap<String, String>();
Map queryMap = new LinkedHashMap();
if (!query.isEmpty() || query.length() > 0) {
sb.append(query);
}
Connection connection = getConnection();
if (connection != null) {
try {
PreparedStatement reportQueryPS = connection.prepareStatement(sb.toString());
ResultSet reportQuery_rst = reportQueryPS.executeQuery();
List<String> tables = new ArrayList<String>();;
if (reportQuery_rst != null) {
StringBuilder selectQuery = new StringBuilder(" SELECT ");
StringBuilder fromQuery = new StringBuilder(" FROM ");
while (reportQuery_rst.next()) {
tableName = reportQuery_rst.getString("tablename");
List<String> columns = resultsMap.get(tableName);
if (columns == null) {
columns = new ArrayList<String>();
resultsMap.put(tableName, columns);
}
columns = resultsMap.get(tableName);
String columnName = reportQuery_rst.getString("columnname");
columns.add(columnName);
}
tableName = "";
for (Entry<String, List<String>> resultEntry : resultsMap.entrySet()) {
tableName = resultEntry.getKey();
List<String> columns = resultEntry.getValue();
int i = 0;
for (String column : columns) {
selectQuery.append(tableName + "." + column);
if (i != columns.size()) {
selectQuery.append(",");
} else {
selectQuery.append("");
}
i++;
}
if (!tables.contains(tableName)) {
tables.add(tableName);
}
}
//to remove comma at the end of line
select = selectQuery.toString().replaceAll(",$", "");
tableName = "";
int i = 0;
for (String table : tables) {
fromQuery.append(table);
fromQuery.append(" ");
fromQuery.append(table);
if (i != tables.size()) {
fromQuery.append(",");
} else {
fromQuery.append("");
}
i++;
}
from = fromQuery.toString().replaceAll(",$", "");
queryMap.put("query", select + from);
}
//from = from+"ORDER BY "+orderbyColumn+" "+sort+" ";
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
closeConnection(connection, null, null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
} else {
System.out.println("Connection not Established. Please Contact Vendor");
}
return queryMap;// return the map/ list which contains query and sory and display order
}
STEP 3 : Result query
{query= SELECT purchase_order.po_number,purchase_order.placed_date,purchase_order.date_closed,purchase_order.scheduled_arrival_date,purchase_order_inventory.unit_cost,purchase_order_inventory.order_quantity,purchase_order_inventory.roll_number,purchase_order_inventory.rec_vendor_quantity,products.product_sku,products.et_conversion_unit_quantity,product_categories.product_category_name ,product_vendors.vendor_name FROM purchase_order purchase_order,purchase_order_inventory purchase_order_inventory,products products,product_categories product_categories,product_vendors product_vendors}
but this not what i wanted, Please help me to construct the query i have given.
Two queries
You need to make two queries:
Query which fields are enabled
Build the second query string (the one you want to build dinamically)
It's this way because a SQL query has to tell which columns will be included before querying any data. In fact it will be used to build the internal DB query plan, it is, the way the DB motor will use to retrieve and organize the data you ask.
Query all columns
Is it necesary to query only that fields? Can't you query everything and use the relevant data?
Joins
Looking at the updated question I guess you need to dynamically add where conditions to join tables correctly. What I should do is have a reference telling me what coindition to add when a table is present.
There are at least two options:
Based on table pairs present (by example: "if A and B are present then add A.col1 = B.col2")
Based on tables present ("if B is present, then add A.col1 = B.col2; A should be present"
Based on your example I think the second option is more suitable (and easy to implement).
So I should have some static Map<String, JoinInfo> where JoinInfo has at least:
JoinInfo
+ conditionToAdd // by example "A.col1 = B.col2"
+ dependsOnTable // by example "A" to indicate that A must be present when B is present
So you can use:
that info to add tables that should be (by example: even if A has no selected cols, must be present to join with B)
include the conditionToAdd to the where clause
Anyway... I think you are getting into much trouble. Why so dynamic?
You have to approach the thing step by step.
Firstly you have to create a query that will return all rows that have status='Y'
Then you will put the COLUMN_NAME in a list of Strings.
List<String> list = new List<String>();
while(rs.next()){
list.add(rs.getString(columnNumber));
}
And then you have to loop the List and generate dynamically your second sql statement
String sqlSelect = "SELECT ";
String sqlFrom = " FROM SOME_OTHER_TABLE "
String sqlWhere = " WHERE SOME_CONDITION = 'SOME_VALUE' "
for(String x : list){
sqlFrom += x +" , "+;
}
//here make sure that you remove the last comma from sqlFrom because you will get an SQLException
String finalSql = sqlSelect + sqlFrom + sqlWhere ;

Categories

Resources