set parameter which is null in #NamedQuery (JPA QL 1.0) - java

I am writing a JPA QL named query that would search for documents. This should be done in only one query and I cannot switch to native SQL (that's non functional requirement).
The query I wrote looks as follows:
query = "select doc from Doc doc " +
" join doc.Csts cst " +
" where cst.cstFrstNm like :FrstNm " +
" and cst.cstLastNm like :LastNm " +
" and doc.resId = :id ";
This query is parametrized using following instructions:
query.setParameter("FrstNm ", firstName + '%');
query.setParameter("LastNm ", lastName + '%');
query.setParameter("id", resId);
firstName, lastName, resId in the above code are my search criteria and they are all Strings and they can be null. When one of them is null, it shouldn't be taken into consideration when the query is invoked.
For instance:
Let's say that: firstName = "John", lastName = "Doe" and resId is null, then the query should return all the entries from Doc table that are for user John Doe, no matter what is their resId.
I was trying to put additional OR and AND conditions into query that'd check if resId is null but it didn't work. I'm testing it on HSQLDB.
Is it any way to modify this JPA query to handle null values?

Two solutions:
First one, don't use a named query and craft a new query for each request:
boolean first = true;
query = query = "select doc from Doc doc " +
" join doc.Csts cst " +
if (firstName != null) {
query += (first ? " where " : " and ");
query += " cst.cstFrstNm like :FrstNm ";
first = false;
}
query += ";";
// ...
Second solution, you are using wildcard. If your parameter is empty, just put a '%' in your query, which will match all corresponding strings:
query.setParameter("FrstNm ", (firstName != null ? firstName : "") + '%');
query.setParameter("LastNm ", (lastName != null ? lastName : "") + '%');
If firstName is empty, your query will look like:
... cst.cstFrstNm like '%' ...
and will match all the values. It will result in the parameter not filtering any result, with a behaviour similar as if it wasn't present.

You may need to build the query dynamically to satisfy your parameters. For instance:
public List<Employee> findEmployees(String name, String deptName, String projectName, String city) {
StringBuffer query = new StringBuffer();
query.append("SELECT DISTINCT e ");
query.append("FROM Employee e LEFT JOIN e.projects p ");
query.append("WHERE ");
List<String> criteria = new ArrayList<String>();
if (name != null) { criteria.add("e.name = :name"); }
if (deptName != null) { criteria.add("e.dept.name = :dept"); }
if (projectName != null) { criteria.add("p.name = :project"); }
if (city != null) { criteria.add("e.address.city = :city"); }
if (criteria.size() == 0) {
throw new RuntimeException("no criteria");
}
for (int i = 0; i < criteria.size(); i++) {
if (i > 0) { query.append(" AND "); }
query.append(criteria.get(i));
}
Query q = em.createQuery(query.toString());
if (name != null) { q.setParameter("name", name); }
if (deptName != null) { q.setParameter("dept", deptName); }
if (projectName != null) { q.setParameter("project", projectName); }
if (city != null) { q.setParameter("city", city); }
return (List<Employee>)q.getResultList();
}
You migt also like to consider Criteria API if you are using JPA 2.0 for this kind of task.

Related

How can I find out the type of sparql query using the code?

String qb = "PREFIX dc: <http://purl.org/dc/elements/1.1/>\n" +
"INSERT DATA\n" +
"{ \n" +
" <http://example/book1> dc:title \"A new book\" ;\n" +
" dc:creator \"A.N.Other\" .\n" +
"}";
// Here I need to check what type of query I got
String type = ... //some code for checking
if (type == "select") {
ParsedTupleQuery q = (ParsedTupleQuery)parser.parseQuery(qb, null);
}else if(type == "costruct") {
ParsedGraphQuery q = (ParsedGraphQuery)parser.parseQuery(qb, null);
}else if(type == "update"){ //here can be insert or delete
ParsedUpdate q = parser.parseUpdate(qb, null);
}
I can't find a way to find out what type of query it is.
Maybe somebody's ever seen it before?
Rdf4j has a QueryParserUtil with a convenience method for this. You can use it as follows:
ParsedOperation operation = QueryParserUtil.parseOperation(QueryLanguage.SPARQL, qb, null);
if (operation instanceof ParsedTupleQuery) {
ParsedTupleQuery q = (ParsedTupleQuery)operation;
...
} else if (operation instanceof ParsedGraphQuery) {
ParsedGraphQuery q = (ParsedGraphQuery)operation;
...
} else if (operation instance ParsedUpdate) {
ParsedUpdate u = (ParsedUpdate)operation;
...
}

Internal server error with SQL query

I am new to hibernate but I have a rough idea on what usually to do, this case, I can't say that is working out. I'm trying to create a filtering system which allows you to sort out different clients in this case with users. My SQL query is working correctly:
SELECT * FROM [de_user_site] WHERE [deactivation_time] = '9999-12-31 00:00:00.000' AND [user_id] IN (SELECT [user_id] FROM [de_users] WHERE [client_id] = 1)
And I've tried to turn that into a java query:
queryStr = "SELECT e FROM DeSiteUser e " + queryStr;
String queryStr = " WHERE e.deactivationTime = '9999-12-31 00:00:00.000' ";
if (clientId != null) {
queryStr += String.format("AND e.userId IN (SELECT id FROM DeUser u WHERE ");
if (clientId != null) {
queryStr += String.format("u.clientId = %d ", clientId);
}
}
However, I am having an issue with this:
Internal Server Error [#500]: org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE, found 'null' near line 1, column 214 [SELECT e FROM com.velatt.dartentitlements.domain.DeSiteUser e WHERE e.deactivationTime = '9999-12-31 00:00:00.000' AND e.userId IN (SELECT id FROM com.velatt.dartentitlements.domain.DeUser u WHERE u.clientId = 6 ]
Does anyone know what I am forgetting, my SQL query is correct but I don't understand why it hasn't worked out for the java query?
You missed close braces. Error says it all.
SELECT e FROM com.velatt.dartentitlements.domain.DeSiteUser e WHERE e.deactivationTime = '9999-12-31 00:00:00.000' AND e.userId IN (SELECT id FROM com.velatt.dartentitlements.domain.DeUser u WHERE u.clientId = 6
Your code should have close braces something like this
queryStr = "SELECT e FROM DeSiteUser e " + queryStr;
String queryStr = " WHERE e.deactivationTime = '9999-12-31 00:00:00.000' ";
if (clientId != null) {
queryStr += String.format("AND e.userId IN (SELECT id FROM DeUser u WHERE ");
queryStr += String.format("u.clientId = %d ", clientId);
queryStr += " ) ";
}
Please replace your given code with below. you have missed to add ')' as the and of subquery.
queryStr = "SELECT e FROM DeSiteUser e " + queryStr;
String queryStr = " WHERE e.deactivationTime = '9999-12-31 00:00:00.000' ";
if (clientId != null) {
queryStr += String.format("AND e.userId IN (SELECT id FROM DeUser u WHERE ");
if (clientId != null) {
queryStr += String.format("u.clientId = %d )", clientId);
}
}

Autonumber reset per day with Java Using Database

I build some software for my mini shop, I really confused with number queue customer who shop in my place. Please someone could help me.
I have a method which content with generate new number of queue from my customer. But when I open my Apps in the next day, I hope the queue is reset into 1 again.
My sytax Java like =
public void acak() {
try {
String generate = "SELECT COALESCE (MAX(no_antrian),0) AS kode from transaksi where tg_transaksi='" + tanggal + "'";
Statement stat = con.createStatement();
ResultSet res = stat.executeQuery(generate);
if (res.next()) {
try {
String kd_barang = res.getString("kode").substring(1);
String AN = "" + (Integer.parseInt(kd_barang) + 1);
String Nol = "";
if (AN.length() == 1) {
Nol = "000";
} else if (AN.length() == 2) {
Nol = "00";
} else if (AN.length() == 3) {
Nol = "0";
} else if (AN.length() == 4) {
Nol = "";
}
lblnoantrian.setText(Nol + AN);
} catch (NumberFormatException ex) {
System.out.println(ex.getMessage());
}
} else {
lblnoantrian.setText("0001");
}
} catch (Exception e) {
e.printStackTrace();
}
}
When I run this program in the next day, I see the eror like :
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:504)
at java.lang.Integer.parseInt(Integer.java:527)
this eror's refers to:
String AN = "" + (Integer.parseInt(kd_barang) + 1);
maybe anyone can helping me..
this is not the proper use of COALESCE
as its description says
Returns the first non-NULL value in the list, or NULL if there are no non-NULL values.
mysql> SELECT COALESCE(NULL,1);
-> 1
mysql> SELECT COALESCE(NULL,NULL,NULL);
-> NULL
in case there is a empty string so its output would be empty string check
SELECT COALESCE (MAX(NULL),0)
->0
SELECT COALESCE (MAX(''),0)
->
SELECT COALESCE ('',0)
->
as you can see the last two queries returns empty string
replace your query with this query i hope this will work
SELECT
CASE
WHEN COALESCE (MAX(no_antrian), 0) = ''
THEN 0
ELSE COALESCE(MAX(no_antrian), 0)
END AS kodec
FROM
transaksi
WHERE tg_transaksi = '" + tanggal + "' "

How to save fields of object into database using jdbc

I'm trying to make my own ORM framework. I get the values from object into arrayList and I'm trying to save them in one time. I have to make for loop to save them all, but I'm confused how to make it?
prepareteState = connect.prepareStatement(Query);
for (int y = 1; y <= obs.size() ; y++) {
for(Object obj : obs){
prepareteState.setObject(y, obj);
System.out.println(Query);
System.out.println(prepareteState.toString());
}
}
prepareteState.execute();
thanks for good advices but, i found the solution :) it is a little bit different than the first idea but, works fine for me:) instead of using prepareState and setObject one by one i`m using StringBuilder to make String and execute query
private String makeInsertQuery(List<String> listOfColumnsNames, List<Object> listOfParameters, String tableName){
StringBuilder columns = new StringBuilder();
StringBuilder parameters = new StringBuilder();
String query = null;
if(listOfColumnsNames != null && listOfColumnsNames.size() != 0 && listOfParameters != null && listOfParameters.size() != 0 && tableName != null){
for(String string : listOfColumnsNames){
columns.append(string + ",");
}
columns.deleteCharAt(columns.length() - 1);
for(Object object : listOfParameters){
parameters.append ("'" + object + "'" + ",");
}
parameters.deleteCharAt(parameters.length() - 1);
query = "INSERT " + "INTO " + tableName + " ( " + columns.toString() + " ) " + " VALUES " + "( " + parameters.toString() + " )" ;
}
//TODO if you need check for null
return query;
}

REFACTOR: Clean dao code for a query with multiple optional params

Is there a possiblity to clean up such a dao method?
I don't like the 2 if's for each param, but there isn't something like "query.setSql()" so i could update the sql after adding the params and building the sql.
public List<OriginLabel> findByCriteria(Link1 l1, Link2 l2, String att) {
String sql = "FROM MyEntity e WHERE 1=1";
if(l1 != null){
sql += " AND e.link1 = :l1 ";
}
if(l2 != null){
sql += " AND e.link2 = :l2 ";
}
if(att != null){
sql += " AND e.attribute = :att ";
}
Query query = getEntityManager().createQuery(sql);
if(l1 != null){
query.setParameter("l1", l1);
}
if(l2 != null){
query.setParameter("l2", l2);
}
if(att != null){
query.setParameter("att", att);
}
return (List<MyEntity>)query.getResultList();
}
I store the parameters in a hashmap in the first if:
public List<OriginLabel> findByCriteria(Link1 l1, Link2 l2, String att) {
String sql = "FROM MyEntity e WHERE 1=1";
HashMap parameters = new HashMap();
if(l1 != null){
sql += " AND e.link1 = :l1 ";
parameters.put("l1", l1);
}
if(l2 != null){
sql += " AND e.link2 = :l2 ";
parameters.put("l2", l2);
}
if(att != null){
sql += " AND e.attribute = :att ";
parameters.put("att", l1);
}
Query query = getEntityManager().createQuery(sql);
SQLUtility.setParameters(query, parameters);
SQLUtility.setParameters (easy to implement, write it yourself) loops over the HashMap keys and sets the parameters on the query.
I would suggest looking into visitor design pattrn.
You can create visitor that visits each of your parameter (which become visitable) and while doing so adds condition to your query string.
Maybe QueryDSL http://www.querydsl.com/ is something you can use to improve your SQL-related code?
When using QueryDSL your statements would be built using only one if per parameter (and your statements will be build statically typed without any string acrobatics) :
public List<OriginLabel> findByCriteria(Link1 l1, Link2 l2, String att) {
QOriginLabel e = QOriginLabel.originLabel;
JPAQuery query = new JPAQuery(em).from(e);
if (l1 != null) {
query.where(e.link1.eq(l1));
}
if (l2 != null) {
query.where(e.link2.eq(l2));
}
if (att != null) {
query.where(e.attribute.eq(att));
}
return query.list(e);
}
If performance is not an issue, I like to code it like this:
public List<OriginLabel> findByCriteria(Link1 l1, Link2 l2, String att) {
String sql = "FROM MyEntity e " +
" WHERE e.link1 = isnull(:l1, e.link1) " +
" AND e.link2 = isnull(:l2, e.link2)" +
" AND e.attribute = isnull(:att, e.attribute)";
Query query = getEntityManager().createQuery(sql);
query.setParameter("l1", l1);
query.setParameter("l2", l2);
query.setParameter("att", att);
return (List<MyEntity>)query.getResultList();
}

Categories