I've got a MySQL table with Foos. Each Foo has a numeric non-unique code and a name. Now I need to find if any Foo with one of certain codes happens to have a name that starts with a given string. In normal SQL this would be trivial:
select * from FOO where CODE in (2,3,5) and NAME like 'bar%';
But how would I properly do this in Spring now? Without the need for the 'like' operator I'd do it like this:
public List<Foo> getByName(List<Integer> codes, String namePart) {
String sql = "select * from FOO where CODE in (:codes) and NAME=:name"
Map<String,Object> params = new HashMap<String,Object>();
params.put("codes", codes);
params.put("name", namePart);
return getSimpleJdbcTemplate().query(sql, new FooRowMapper(), params);
}
However, with 'like' nothing seems to work: NAME like :name%, NAME like ':name%', or NAME like ?% when using the placeholders instead of named parameters.
I could be brutal and enter it as
String sql = "select * from FOO where CODE in (:codes) and NAME like '"+namePart+"%'";`
but obviously it would be more than nice if Spring would sanitize the input parameters properly etc, you know...
You'd think Spring would support this somehow but I cannot figure it out.
Wait, of course I had to "try one more final thing" before calling it a day, and lo and behold, all my unit tests suddenly pass:
public List<Foo> getByName(List<Integer> codes, String namePart) {
String sql = "select * from FOO where CODE in (:codes) and NAME like :name"
Map<String,Object> params = new HashMap<String,Object>();
params.put("codes", codes);
params.put("name", namePart+"%");
return getSimpleJdbcTemplate().query(sql, new FooRowMapper(), params);
}
I didn't think of entering the "%" in the parameter, I was certain Spring would automatically escape it. I wonder if I'm doing it right?
For named parameters to work, you need to use NamedParameterJdbcTemplate
params.put("name", "Joe%");
jdbcTemplate.query("select * from FOO where CODE in (:codes) and NAME like :name"
In another form, I encountered the same problem, and I tried to solve it via this manner:
public List<MyEntity> getMyEntityValuesBySearchText(String searchText) {
String query = "SELECT * FROM MY_ENTITY_TABLE WHERE NAME LIKE ?";
return this.getJdbcTemplate().query(query, new String[] { "%" + searchText + "%" },
(rs, rowNum) -> new MyEntity(rs.getLong("PK"), rs.getString("NAME")));
}
There is a problem with the code above. The code structure is correct but there is a problem in mapping the variable. You will get the error message as "Index Out of Bound" SQL Exception error.
To avoid that error we map our variable properly using the class "MySqlParameterSource". We needed to create an object for that class and pass our variable inside to map out variables.
Follow this as an example.
public List<Products> getParticular2(#RequestParam String charc){
String sql ="select * from products where name like :name";
Map<String, Object> params = new HashMap<String, Object>();
params.put("name", charc+"%");
MapSqlParameterSource param = new MapSqlParameterSource(params);
List <Products> list = template.query(sql, param, new
BeanPropertyRowMapper<>(Products.class));
return list;
}
Related
The idea behind parametrized queries is to re-use (cache) execution plans.
If a node label or a relationship type do not vary, the execution plan would be the same at all, thus benefits can be achieved of execution plan caching.
Currently, I'm my complete Cypher Query is built using Java String Building. Instead of creating the entire Cypher Query using String building I want to pass the values of the Properties as Parameter Values along with Property Names as Parameters or not. I need sample code, guidance for the same.
My Current Code
import org.neo4j.driver.v1.AuthTokens;
import org.neo4j.driver.v1.Driver;
import org.neo4j.driver.v1.GraphDatabase;
import org.neo4j.driver.v1.Session;
public class ForStackoverflowQuestion {
public static void main(String[] args) {
Driver driver = GraphDatabase.driver(
"bolt://localhost:7687", AuthTokens.basic("neo4j", "12345"));
Session session = driver.session();
String Node1 = "Software_Engineer";
String Node2 = "Programming_Language";
String relationBetweenNode1andNode2 = "LEARNS";
String PersonNameAttribute = "name";
String PersonNameValue = "Jaykant";
String ProgrammingLanguageAttribute = "version";
String ProgrammingLanguageValue = "Neo4j";
String t = "MERGE(n1:"+Node1+"{"+PersonNameAttribute+":\""+PersonNameValue+"\"})"+"-[:"+relationBetweenNode1andNode2+"]->(n2:" + Node2 +" {"+ProgrammingLanguageAttribute+":'"+ProgrammingLanguageValue+"'})";
System.out.println(t);
session.run(t);
session.close();
driver.close();
}
}
I understand that my above code is not using Parameterized Cypher Query; so it will not generate any Query Plan in neo4j.
In order to use and benefit from the Query Plan, I need to use the Parametrized Query.
If not Node1, Node2, and relationBetweenNode1andNode2 as Parameters then at least following values can be passed as parameters.
PersonNameAttribute = "name";
PersonNameValue = "Jaykant";
ProgrammingLanguageAttribute = "version";
ProgrammingLanguageValue = "Neo4j";
Any sample code? Tutorial?
You can pass parameters along with query in session.run() method.
Ex.
session.run(query, parameters)
Parameters should be a Map.
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("PersonNameValue", "Jaykant");
parameters.put("ProgrammingLanguageValue", "Neo4j");
Query can be modified as:
String t = "MERGE (n1:"+Node1+"{"+PersonNameAttribute+":{PersonNameValue}})"+"-[:"+relationBetweenNode1andNode2+"]->(n2:" + Node2 +" {"+ProgrammingLanguageAttribute+": {ProgrammingLanguageValue}})";
Finally run statement:
session.run(t, parameters);
I have a code which gets a body POST from Postman:
#RequestMapping(value="/dep", method=RequestMethod.POST)
public JsonResponse dep(#RequestBody String body) throws SQLException {
Connection connection = ConnectionSingleton.getInstance().getConnection(env);
Statement statement = connection.createStatement();
statement.close();
connection.close();
System.out.println("BODY #### "+body);
return new JsonResponse("depreciated");
}
Postman sent:
{
"idn":"MLCM00292",
"monto":"9149.92"
}
And the string is like:
%7B%0A%09%22idn%22%3A%22MLCM00292%22%2C%0A%09%22monto%22%3A%229149.92%22%0A%7D=
The words in bold are the parameters and their assigned values. I want to receive the parameters like variable. What its the correct way to get the params from a body in a POST request? What is missing in my code?
You can use a Map like this:
public JsonResponse dep(#RequestBody Map<String, String> body)
and then inside the method get the values like this:
String id = body.get("idn");
String monto = body.get("monto");
You can change the generics type for the Map class as it fits your needs. For example, if you are going to receive values of different types you can use it like Map<String, Object> body, then you could parse every value according to the data type (which you must know in advance). Something like:
String id = body.get("idn").toString();
double monto = Double.parseDouble(body.get("monto").toString());
For more complex data type I recommend you to create some custom POJOs or JavaBeans.
Further readings
Difference between DTO, VO, POJO, JavaBeans?
I am relatively new to Java MyBatis. I came across SQL Builder class in MyBatis. However, I don't understand how to handle the result of the SELECT SQL query, especially if the columns are going to be different in each case while using SQL Builder. Is there an example which can help me understand how to write this?
Usually, I use Mapper XML files with ResultMap to retrieve the output of an SQL statement.
I figured out the way to get it to work. I am not sure if it is the correct way.
In the XML I made the following entry
<select id="readSignals" resultType="map">
${query}
</select>
The ${query} is passed from a QueryBuilder class and the resultType is set to "map". This cause myBatis to return a List> where each Map in the list is a row. The String contains the column name and Object contains the data.
I use the following code to convert the List> into JSON.
public static JSONObject convertToJSON(List<Map<String, Object>> queryData) {
JSONObject queryJSONOutput = new JSONObject();
JSONArray outputArray = new JSONArray();
queryData.stream().forEach(d -> {
JSONObject jsonObject = new JSONObject();
for (String key: d.keySet()) {
jsonObject.put(key, d.get(key));
}
outputArray.put(jsonObject);
});
queryJSONOutput.put("data", outputArray);
return queryJSONOutput;
}
Let's say I have a page which lists things and has various filters for that list in a sidebar. As an example, consider this page on ebuyer.com, which looks like this:
Those filters on the left are controlled by query string parameters, and the link to remove one of those filters contains the URL of the current page but without that one query string parameter in it.
Is there a way in JSP of easily constructing that "remove" link? I.e., is there a quick way to reproduce the current URL, but with a single query string parameter removed, or do I have to manually rebuild the URL by reading the query string parameters, adding them to the base URL, and skipping the one that I want to leave out?
My current plan is to make something like the following method available as a custom EL function:
public String removeQueryStringParameter(
HttpServletRequest request,
String paramName,
String paramValue) throws UnsupportedEncodingException {
StringBuilder url = new StringBuilder(request.getRequestURI());
boolean first = true;
for (Map.Entry<String, String[]> param : request.getParameterMap().entrySet()) {
String key = param.getKey();
String encodedKey = URLEncoder.encode(key, "UTF-8");
for (String value : param.getValue()) {
if (key.equals(paramName) && value.equals(paramValue)) {
continue;
}
if (first) {
url.append('?');
first = false;
} else {
url.append('&');
}
url.append(encodedKey);
url.append('=');
url.append(URLEncoder.encode(value, "UTF-8"));
}
}
return url.toString();
}
But is there a better way?
The better way is to use UrlEncodedQueryString.
UrlEncodedQueryString can be used to set, append or remove parameters
from a query string:
URI uri = new URI("/forum/article.jsp?id=2¶=4");
UrlEncodedQueryString queryString = UrlEncodedQueryString.parse(uri);
queryString.set("id", 3);
queryString.remove("para");
System.out.println(queryString);
We are using Neo4j 2.0 RC1 embedded in our java server. We parametrize the variables in our cyphers. One of our cyphers uses IN clause e.g.
MATCH (a) WHERE a.name IN ["Peter", "Tobias"] RETURN a
So i tried something like this:
String cypher = "MATCH (a) WHERE a.name IN {names} RETURN a";
Map<String, Object> params = new HashMap<>();
List<String> names = new ArrayList<>();
//add some names to the names list
params.put("names", names);
ExecutionResult result = engine.execute(cypher, params);
Its obviously not working, how do i parametrize IN operator ?
neo4j rocks !!
Things work as expected / desired. I got a bug elsewhere in the code otherwise the following snippet works just fine:
String cypher = "MATCH (a) WHERE a.name IN {names} RETURN a";
Map<String, Object> params = new HashMap<>();
List<String> names = new ArrayList<>();
//add some names to the names list
params.put("names", names);
ExecutionResult result = engine.execute(cypher, params);