Query works fine in MySql but returns no records with JdbcTemplate - spring

I have the following service method:
public Page<ProductSalesReportLineDto> getReport(
Unit unit, Organization customer, Organization supplier, Date startDate, Date endDate, Pageable pageable
){
List<ProductSalesReportLineDto> lines = new ArrayList<ProductSalesReportLineDto>();
String sql = "SELECT product.id, product.code as code, product.barcode as barcode, product_name.name__text AS name, " +
"SUM(order_line.quantity) as quantity, SUM(order_line.commissioned_price_price * order_line.quantity) as price " +
"FROM product LEFT JOIN order_line ON order_line.product_id = product.id " +
"JOIN `order` ON order_line.order_id = order.id " +
"JOIN product_name ON product_name.product_id = product.id " +
"WHERE product_name.name__locale = \"en-US\" " +
"AND (:customer is null OR :customer='' OR `order`.customer_id = :customer) " +
"AND (:supplier is null OR :supplier='' OR `order`.supplier_id = :supplier) " +
"AND (:startDate is null OR :startDate='' OR `order`.date >= :startDate) " +
"AND (:endDate is null OR :endDate='' OR `order`.date <= :endDate) " +
"AND (:unit is null OR :unit='' OR product.unit = :unit) " +
"GROUP BY product.id, product_name.name__text " +
"LIMIT :offset, :pageSize";
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("offset", pageable.getOffset());
parameters.put("pageSize", pageable.getPageSize());
parameters.put("customer", customer != null ? customer.id : null);
parameters.put("supplier", supplier != null ? supplier.id : null);
parameters.put("startDate", startDate);
parameters.put("endDate", endDate);
parameters.put("unit", unit);
List<Map<String, Object>> rows = namedParameterJdbcTemplate.queryForList(sql, parameters);
for (Map<String, Object> row : rows) {
ProductSalesReportLineDto line = new ProductSalesReportLineDto();
line.productName = row.get("name") != null ? row.get("name").toString() : "";
line.productCode = row.get("code") != null ? row.get("code").toString() : "";
line.productBarcode = row.get("barcode") != null ? row.get("barcode").toString() : "";
line.quantity = row.get("quantity") != null ? Double.parseDouble(row.get("quantity").toString()) : 0;
line.price = row.get("price") != null ? Double.parseDouble(row.get("price").toString()) : 0;
lines.add(line);
}
Page<ProductSalesReportLineDto> page = new PageImpl<ProductSalesReportLineDto>(lines);
return page;
}
The parameters come from a #RestController method:
public #ResponseBody
ResponseEntity<?> get(
#RequestParam(value = "unit", required = false) Unit unit,
#RequestParam(value = "customer", required = false) Organization customer,
#RequestParam(value = "supplier", required = false) Organization supplier,
#DateTimeFormat(pattern = "yyyyy-MM-dd") #RequestParam(value = "startDate", required = false) Date startDate,
#DateTimeFormat(pattern = "yyyyy-MM-dd") #RequestParam(value = "endDate", required = false) Date endDate,
Pageable pageable
)
And Unit is an enum type field on Product:
#Enumerated(EnumType.STRING)
public Unit unit;
public enum Unit {
ROLL("ROLL", "ROLL", AbstractUnit.ONE),
METRE("METRE", Units.METRE.getSymbol(), Units.METRE),
KILOGRAM("KILOGRAM", Units.KILOGRAM.getSymbol(), Units.KILOGRAM),
PIECE("PIECE", "PIECE", AbstractUnit.ONE),
SAMPLE("SAMPLE", "SAMPLE", AbstractUnit.ONE);
I cannot retrieve products by unit using this query. With MySql the query works fine and it returns records. For example:
SELECT product.id, product.code as code, product.barcode as barcode, product_name.name__text AS name, SUM(order_line.quantity) as quantity, SUM(order_line.commissioned_price_price) as price FROM product LEFT JOIN order_line ON order_line.product_id = product.id JOIN `order` ON order_line.order_id = `order`.id JOIN product_name ON product_name.product_id = product.id WHERE product_name.name__locale = "en-US" AND (null is null OR null='' OR `order`.customer_id = null) AND (null is null OR null='' OR `order`.supplier_id = null) AND (null is null OR null='' OR `order`.date >= null) AND (null is null OR null='' OR `order`.date <= null) AND ("ROLL" is null OR "ROLL"='' OR product.unit = "ROLL") GROUP BY product.id, product_name.name__text
This query returns one row. When I run the same query via the rest interface and NamedParameterJdbcTemplate it returns no records. Can anybody tell what I am missing?
Following code also returns one row:
String sql2 = "SELECT * FROM product WHERE product.unit = :unit";
Map<String, Object> parameters2 = new HashMap<String, Object>();
parameters2.put("unit", "ROLL");
List<Map<String, Object>> rows2 = namedParameterJdbcTemplate.queryForList(sql2, parameters2);

Related

Adding parameters optionally to Spring Data JPA Native query

I am using Spring Data JPA with native queries like below
public interface ItemRepository extends JpaRepository<ItemEntity, Long> {
#Query(value = "select * from items i where i.category = :itemCategory and i.item_code = :itemCode", nativeQuery = true)
Page<ItemEntity> search(#Param("itemCategory") String itemCategory, #Param("itemCode") String itemCode, Pageable pageable);
}
Now, my use case is
It itemCode is available, only the item with that code from that category should be returned.
But if itemCode is not available then all items in that category should be returned.
So the problem with the above category is when itemCode is passed as NULL no data is returned since it does not match anything. whereas the requirement is it should be ignored.
So is there a way to optionally add a clause to Spring Data JPA native query. I know it is possible with CriteriaQuery but can we do something similar for native queries?
Thanks
Yes, it's feasible with native query too. Very Good explanation here read this
#Approach1
#NamedQuery(name = "getUser", query = "select u from User u"
+ " where (:id is null or u.id = :id)"
+ " And :username"
:itemCode is null or i.item_code = :itemCode
#Approach2
# UserDao.java
public User getUser(Long id, String usename) {
String getUser = "select u from user u where u.id " + Dao.isNull(id)
+ " And u.username " + Dao.isNull(username);
Query query = Dao.entityManager.createQuery(getUser);
}
# Dao.java
public static String isNull(Object field) {
if (field != null) {
if (field instanceof String) {
return " = " + "'" + field + "'";
} else {
return " = " + field;
}
} else {
return " is NULL ";
}
}
How to handle null value of number type in JPA named query
Just modify the where condition
i.item_code = :itemCode
to
:itemCode is null or i.item_code = :itemCode

i am trying to join 3 tables below is the code

var result = (from p in db.push_notifications
join nu in db.notification_recievers on p.id equals nu.push_notification_id
join nt in db.notification_types on p.notification_type_id equals nt.id
where (p.id == pushNotificationId && p.send_criteria == criteria && nu.delete_flag == false && p.delete_flag == false && nt.delete_flag == false)
select new NotificationList
{
conferenceId = p.conference_id,
pushNotificationId = p.id,
notificationId = nt.id,
notificationType = nt.notification_type,
nottificationDate = p.created_dt_tm,
criteria = (int)p.send_criteria,
notificationMessage = p.notification_msg,
userEmail=null,
userInterests = **getInterestNamesByPushNotificationId(p.id)**,
userEvents=null
}).Distinct();
public string getInterestNamesByPushNotificationId(int id)
{
string interests = string.Empty;
var query = from i in db.interests
join pn in db.notification_recievers
on i.id equals pn.interest_id
where pn.push_notification_id == id && pn.delete_flag == false
select new
{
name = i.name
};
foreach (var intr in query.Distinct())
{
if (interests == "")
{
interests = intr.name;
}
else
{
interests = interests + ", " + intr.name;
}
}
return interests;
}
this is throwing me error
LINQ to Entities does not recognize the method 'System.String
getInterestNamesBy PushNotification(Int32)' method, and this method
cannot be translated into a store expression.
The Entity Framework is trying to execute your LINQ clause on the SQL side, obviously there is no equivalent to 'getInterestNamesBy PushNotification(Int32)' from a SQL perspective.
You need to force your select to an Enumerable and then reselect your object using the desired method.
Not ideal but something like this should work - (not tested this so be nice).
var result = (from p in db.push_notifications
join nu in db.notification_recievers on p.id equals nu.push_notification_id
join nt in db.notification_types on p.notification_type_id equals nt.id
where (p.id == pushNotificationId && p.send_criteria == criteria && nu.delete_flag == false && p.delete_flag == false && nt.delete_flag == false)
select new { p=p, nu = nu, nt = nt }).AsEnumerable().Select( x => new NotificationList()
{
conferenceId = x.p.conference_id,
pushNotificationId = x.p.id,
notificationId = x.nt.id,
notificationType = x.nt.notification_type,
nottificationDate = x.p.created_dt_tm,
criteria = (int)x.p.send_criteria,
notificationMessage = x.p.notification_msg,
userEmail=null,
userInterests = getInterestNamesByPushNotificationId(x.p.id),
userEvents=null
}).Distinct();
i have done it this way
In my model
using (NotificationService nService = new NotificationService())
{
modelView = nService.DetailsOfNotifications(pushNotificationId, criteriaId).Select(x => new NotificationViewModelUI(x.conferenceId, x.pushNotificationId, x.notificationId, x.notificationType, x.nottificationDate, x.criteria, x.notificationMessage, x.userEmail, nService.getInterestNamesByPushNotificationId(x.pushNotificationId), nService.getIEventTitlesByPushNotificationId(x.pushNotificationId))).ToList();
}
public NotificationViewModelUI(int conferenceId, int pushNotificationId, int notificationId, string notificationType, DateTime dateTime, int criteria, string nMessage, string emailId = null, string interestNames = null, string eventTitles = null)
{
this.conferenceId = conferenceId;
this.pushNotificationId = pushNotificationId;
this.notificationId = notificationId;
this.notificationType = notificationType;
this.notificationDate = dateTime;
this.sendCriteria = (NotificationCriteria)criteria;
this.notificationMessage = nMessage;
this.emailId = NotificationCriteria.SpecificUser.Description() +"... "+ emailId;
this.interestNames = NotificationCriteria.UserByInterests.Description() + "... " + interestNames;
this.eventTitles = NotificationCriteria.UserByEvents.Description() + "... " + eventTitles;
}

how to pass string variable to linq select new {} section

Ii just want to make search functionality with linq with multiple ColumnNames that stored to session variable. I'm using one method:
public void FillGrid(string CommandName,string ColumnName, string SearchText)
That has three string variable that stores session value.
Now I just want to pass ColumnName with this query:
var query1 = (from p in db.Posts
join c in db.Categories on p.Category_id equals c.Id
join u in db.Users on p.User_id equals u.Id
where (p.ToUser_id == user_id || p.ToUser_id == null) && p.User_id != user_id
orderby p.Sent_Datetime descending
select new
{
Id = p.Id,
Title = p.Title,
Publisher = u.First_name + " " + u.Last_name,
ToUser = p.ToUser_id,
PublishDate = p.Sent_Datetime,
IsFile = p.IsFileAttached,
CategoryName = c.Category_name,
status_name = (from s in db.Status where (s.Id == p.status_id) select s.status_name).FirstOrDefault(),
Group_name = (from g in db.Groups where (g.Id == p.group_id) select g.Group_name).FirstOrDefault(),
FileSize = p.TotalFileSize,
ColumnName = Sesssion["ColumnName"].ToString()
}).Where(q => q.ColumnName.Contains(SearchText));
However, ColumnName does not give any text or it may be not part of this query i have to manually give column name because.
for multiple column i have, so i can not use this statement like:
.Where(q => q.Tile.Contains(SearchText));
this query works fine with single column. but there is multiple column i have so i have to set q.ColumnName from outer side.
I would do an extension method for that kind of things, building an expression for your predicate.
public static class Helper
{
public static IQueryable<T> FilterForColumn<T>(this IQueryable<T> queryable, string colName, string searchText)
{
if (colName != null && searchText != null)
{
var parameter = Expression.Parameter(typeof(T), "m");
var propertyExpression = Expression.Property(parameter, colName);
var searchExpression = Expression.Constant(searchText);
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var body = Expression.Call(propertyExpression, containsMethod, searchExpression);
var predicate = Expression.Lambda<Func<T, bool>>(body, new[] { parameter });
return queryable.Where(predicate);
}
else
{
return queryable;
}
}
}
usage in your case
var query1 = (from p in db.Posts
join c in db.Categories on p.Category_id equals c.Id
join u in db.Users on p.User_id equals u.Id
where (p.ToUser_id == user_id || p.ToUser_id == null) && p.User_id != user_id
orderby p.Sent_Datetime descending
select new
{
Id = p.Id,
Title = p.Title,
Publisher = u.First_name + " " + u.Last_name,
ToUser = p.ToUser_id,
PublishDate = p.Sent_Datetime,
IsFile = p.IsFileAttached,
CategoryName = c.Category_name,
status_name = (from s in db.Status where (s.Id == p.status_id) select s.status_name).FirstOrDefault(),
Group_name = (from g in db.Groups where (g.Id == p.group_id) select g.Group_name).FirstOrDefault(),
FileSize = p.TotalFileSize,
}).FilterForColumn(Sesssion["ColumnName"].ToString(), SearchText);

Spring JdbcTemplate query parameters type error: Invalid column type

I use Spring Jdbc Template that way:
public List<User> getUsersForGrid(int rows, int page, String sidx,
String sord) {
int fromRecord = 0;
int toRecord = 0;
toRecord = page * rows;
fromRecord = (page - 1) * rows;
StringBuilder sqlB = new StringBuilder();
sqlB.append("SELECT user_id, username ");
sqlB.append("FROM users ");
sqlB.append("WHERE :fromRecord <= rownum AND rownum <= :toRecord ");
sqlB.append("ORDER BY %s %s ");
String sql = String.format(sqlB.toString(), sidx, sord);
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("fromRecord", fromRecord);
params.addValue("toRecord", toRecord);
List<Map<String, Object>> rsRows = this.jdbcTemplate.queryForList(sql
.toString(),params);
List<User> users = new ArrayList<User>();
for (Map<String, Object> row : rsRows) {
BigDecimal id = (BigDecimal) row.get("user_id");
String username = (String) row.get("username");
User user = new User(id.intValue(), username);
users.add(user);
}
return users;
}
and get java.sql.SQLException: Invalid column type
sidx is column nate("user_id" for example) sord is asc/desc
When pass no params(execute only
sql.append("SELECT user_id, username ");
sql.append("FROM users ");
) everything is OK.
Update: Works with:
sqlB.append("WHERE ? <= rownum AND rownum <= ? ");
and
this.jdbcTemplate.queryForList(sql.toString(),new Object[]{fromRecord, toRecord});
Seems like problem with Spring MapSqlParameterSource and named parameters. I use Spring 3.1.3
DB is Oracle 11.2
describe users;
Name Null Type
------------------------------ -------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
USER_ID NOT NULL NUMBER
USERNAME NOT NULL VARCHAR2(40)
PASSWORD NOT NULL VARCHAR2(20)
ENABLED NOT NULL NUMBER
I think the problem is with your order by clause,
you are trying to dynamically change your order by clause.
Just try
StringBuilder sql = new StringBuilder();
sql.append("SELECT user_id, username ");
sql.append("FROM users ");
sql.append("WHERE :fromRecord <= rownum AND rownum <= :toRecord ");
sql.append("ORDER BY user_id asc ");
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("fromRecord", fromRecord);
params.addValue("toRecord", toRecord);
If the above works, then instead of using the MapSqlParameterSource for changing the order by clause use something like
StringBuilder sql = new StringBuilder();
sql.append("SELECT user_id, username ");
sql.append("FROM users ");
sql.append("WHERE :fromRecord <= rownum AND rownum <= :toRecord ");
sql.append("ORDER BY %s %s ");
//Format the sql string accordingly
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("fromRecord", fromRecord, Types.INTEGER);
params.addValue("toRecord", toRecord, Types.INTEGER);
Hope it helps.
try this
List<Map> rows = getJdbcTemplate().queryForList(sql);
for (Map row : rows) {
BigDecimal id = (BigDecimal) row.get("user_id");
String username = (String) row.get("username");
User user = new User(id.intValue(), username);
users.add(user);
}
ok try
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("fromRecord", fromRecord);
namedParameters.addValue("toRecord", toRecord);
namedParameters.addValue("sidx", sidx);
namedParameters.addValue("sord", sord);
return this.getNamedParameterJdbcTemplate().query(query,
namedParameters, new UserElementMapper());
public class UserMapper implements RowMapper<User> {
public EmailElement mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
emailElement.setID(rs.getInt("user_id"));
emailElement.setUsernameo(rs.getString("username"));
return user;
}
}

Spring JDBC Framework Conditional Prepared Statement

public ResultSet getAdCampaignDetailsbyName(ADCampaignDetails Obj,
Connection conn, ResultSet rs, PreparedStatement pstmt) throws SQLException {
String query = "select adCampaignName,adCampaignId from AdCampaignDetails";
query += " where 1=1 ";
if (Obj.getAdCamapignName() != null)
query += " and adCampaignName = ?";
if (Obj.userId != "")
query += " and userId = ?";
pstmt = conn.prepareStatement(query);
int i = 0;
if (Obj.getAdCamapignName() != null)
pstmt.setString(++i, Obj.getAdCamapignName());
if (Obj.userId != "")
pstmt.setString(++i, Obj.userId);
System.out.println(" Q : " + query);
rs = pstmt.executeQuery();
return rs;
}
I am new to Spring , in this above query, i have used two conditions , How to execute query with condition in Spring JDBC Framework?
You can use SimpleJDBCTemplate.
// SQL query
String query = "select adCampaignName,adCampaignId from AdCampaignDetails where 1=1";
// Map with parameter value
Map<String, Object> parameters = new HashMap<String, Object>();
if (adCampaignName!=null){
parameters.put("adCampaignName ", adCampaignName );
query += " AND adCampaignName = :adCampaignName";
}
if (userId!=null){
parameters.put("userId", 1);
query += " AND userId= :userId";
}
// Execute query using simpleJDBC Template
List<AdCampaignDetails> resultList = getSimpleJdbcTemplate().query(query, new customRowMapper(), parameters);
You can build the query string accordingly, just add coresponding entries in map.
Check this link for details.

Resources