When to use Map and SqlParameterSource in namedParameterJdbcTemplate? - spring-jdbc

String SQL = "INSERT INTO Employee (name, age, salary) VALUES (:name,:age,:salary)";
Map namedParameters = new HashMap();
namedParameters.put("name", name);
namedParameters.put("age", age);
namedParameters.put("salary", salary);
namedParameterJdbcTemplate.update(SQL, namedParameters);
String SQL = "UPDATE Employee SET age = :age WHERE empid = :empid";
SqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("age", age);
namedParameters.addValue("empid", empid);
namedParameterJdbcTemplate.update(SQL, namedParameters);
Seems both Map and SqlParameterSource are same. But why did API developers added these API's ? Is there any particular scenario to use Map or SqlParameterSource which makes execution faster? Please explain me clearly. Thanks in advance.

Using a Map is fine for simple cases, but there are two benefits to using SqlParamaterSource over a Map.
The first is simply the builder pattern allowing you to add multiple values inline (namedParameters.addValue().addValue().addValue() etc).
The second is more powerful. The jdbcTemplate will auto-determine the sqlType of your map values while the SqlParamaterSource allows you to explicitly use the sqlType of your choice. This can be an issue depending on your database, indexes and parameters.
An example would be Integers and Longs with an Oracle database. The jdbc template will add these objects to your query with surrounding quotes '' making them effectively strings in your database query. If you have a number in your database with leading 0's it will not be found because '0XXXX' will not match 'XXXX'. If you pass in the right sqlType, the jdbc template will do a number comparison without quotes so XXXX will equal XXXX.

When my place holder values were of different datatypes, this (MapSqlParameterSource) really helped me:
String SQL = "UPDATE Employee SET joindate = :joinDate WHERE empid = :empid";
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("date", joinDate, Types.Date);
namedParameters.addValue("empid", empid, Types.Integer);
namedParameterJdbcTemplate.update(SQL, namedParameters);

Related

Is it possible to use Oracle's sysdate with jdbcTemplate

So far I tried
jdbcTemplate.update("INSERT INTO INFO (id, my_date)
"VALUES(?, ?)", 1, "sysdate");
Also tried with namedParameterJdbcTemplate by just using a map.
Map namedParameters = new HashMap();
namedParameters.put("id", 1);
namedParameters.put("my_date", "sysdate");
namedParameterJdbcTemplate.update("INSERT INTO INFO (id, my_date)
"VALUES(:id, :my_date)",namedParameters);
After trying all the above the the Exception is is below
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [INSERT INTO INFO (id, my_date)
"VALUES(?, ?)]; ORA-01858: a non-numeric character was found where a numeric was expected
; nested exception is java.sql.SQLDataException: ORA-01858: a non-numeric character was found where a numeric was expected
at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:82) ~[spring-jdbc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) ~[spring-jdbc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82) ~[spring-jdbc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:655) ~[spring-jdbc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
Found this link, where they claim is possible. I don't see how, unless I am doing something wrong. Any suggestion?
http://forum.spring.io/forum/spring-projects/data/99020-is-it-possible-to-use-oracle-s-sysdate-with-simplejdbcinsert
As an alternative, you could use the current timestamp available in Java:
Timestamp sysdate = new Timestamp(System.currentTimeMillis());
Map namedParameters = new HashMap();
namedParameters.put("id", 1);
namedParameters.put("my_date", sysdate);
Your Java code doesn't know what sysdate is, it's a specific variable within the Oracle database. In a similar vein to Tim's answer I would specify a java variable in your code, albeit in a similar format to your second attempt:
Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put("id", 1);
namedParameters.put("my_date", new Date());//java.util.Date
jdbcTemplate.update("INSERT INTO info (id, my_date) VALUES (:id, :my_date)", namedParameters);

Android SQLITE Insert into table with values coming from a subquery

In my db-driven app I need to perform insert into queries in which the value for one or more field comes from a subquery.
The insert into statement may look like the following example:
INSERT INTO MyTable (field_1, field_2)
VALUES('value for field 1', (SELECT field_x FROM AnotherTable WHERE ...))
At present I am doing it manually building the query:
String MyQuery = "INSERT INTO mytable (field_1, field_2)
VALUES('value for field 1', (SELECT field_x FROM AnotherTable WHERE ...))"; // Of course my query is far more complex and is built in several steps but the concept is safe, I end up with a SQL String
SQLiteDatabase= db = getWritableDatabase();
db.execSQL(MyQuery); // And it works flawlessy as it was a Swiss Clock
What i would like to do instead is:
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("field_1", "value for field 1");
values.put("field_2", ThisIsAQuery("(SELECT field_x FROM AnotherTable WHERE ...)"));
db.insert("MyTable", null, values);
db.close();
Where the fake method ThisIsAQuery(...) is the missing part, something that should tell the query builder that "SELECT.." is not a value but a query that should be embedded in the insert statement.
Is there a way to achieve this?
The whole point of the ContentValues container is to be able to safely use strings without interpreting them as SQL commands.
It is not possible to use subqueries with insert(). The only way to get a value from another table is by executing a separate query; in this case, ThisIsAQuery() would be stringForQuery() or longForQuery().

nature of SELECT query in MVC and LINQ TO SQL

i am bit confused by the nature and working of query , I tried to access database which contains each name more than once having same EMPid so when i accessed it in my DROP DOWN LIST then same repetition was in there too so i tried to remove repetition by putting DISTINCT in query but that didn't work but later i modified it another way and that worked but WHY THAT WORKED, I DON'T UNDERSTAND ?
QUERY THAT DIDN'T WORK
var names = (from n in DataContext.EmployeeAtds select n).Distinct();
QUERY THAT WORKED of which i don't know how ?
var names = (from n in DataContext.EmployeeAtds select new {n.EmplID, n.EmplName}).Distinct();
why 2nd worked exactly like i wanted (picking each name 1 time)
i'm using mvc 3 and linq to sql and i am newbie.
Both queries are different. I am explaining you both query in SQL that will help you in understanding both queries.
Your first query is:
var names = (from n in DataContext.EmployeeAtds select n).Distinct();
SQL:-
SELECT DISTINCT [t0].[EmplID], [t0].[EmplName], [t0].[Dept]
FROM [EmployeeAtd] AS [t0]
Your second query is:
(from n in EmployeeAtds select new {n.EmplID, n.EmplName}).Distinct()
SQL:-
SELECT DISTINCT [t0].[EmplID], [t0].[EmplName] FROM [EmployeeAtd] AS
[t0]
Now you can see SQL query for both queries. First query is showing that you are implementing Distinct on all columns of table but in second query you are implementing distinct only on required columns so it is giving you desired result.
As per Scott Allen's Explanation
var names = (from n in DataContext.EmployeeAtds select n).Distinct();
The docs for Distinct are clear – the method uses the default equality comparer to test for equality, and the default comparer sees 4 distinct object references. One way to get around this would be to use the overloaded version of Distinct that accepts a custom IEqualityComparer.
var names = (from n in DataContext.EmployeeAtds select new {n.EmplID, n.EmplName}).Distinct();
Turns out the C# compiler overrides Equals and GetHashCode for anonymous types. The implementation of the two overridden methods uses all the public properties on the type to compute an object's hash code and test for equality. If two objects of the same anonymous type have all the same values for their properties – the objects are equal. This is a safe strategy since anonymously typed objects are essentially immutable (all the properties are read-only).
Try this:
var names = DataContext.EmployeeAtds.Select(x => x.EmplName).Distinct().ToList();
Update:
var names = DataContext.EmployeeAtds
.GroupBy(x => x.EmplID)
.Select(g => new { EmplID = g.Key, EmplName = g.FirstOrDefault().EmplName })
.ToList();

Using dates with Cassandra

I've just started my adventure with Cassandra database. I've managed to learn some basics but what I still can't understand is how to work with dates in Cassandra?
So for example in MySQL we have a datetime type for a field and we can query (for example) all fields with creation date less then 2010-01-01. Furthermore we can order the result by creation date field.
How can we achieve the same with Cassandra? How to define the corresponding Column Family and how to query (CQL) it to get the same result?
You can use type DateType to define a column of type DateType in your column family. You should really read this page, it has description and example how to do range query (that is creationdate < 2010-01-01). For ordering, you can refer to the SliceRange but this will probably cover in the cassandra client already. You will probably want to look into the cassandra client to do the query.
This is a snippet on how to do query in cassandra using hector client.
// 2010-01-01
Date date = new Date(1262275200L);
try
{
getConnection();
IndexedSlicesQuery<String, String, String> indexedSlicesQuery = HFactory.createIndexedSlicesQuery(keyspace, ss, ss, ss);
indexedSlicesQuery.setColumnNames("name");
indexedSlicesQuery.addLtExpression("timestamp", ByteBufferUtil.string(date_s.toByteBuffer(date)));
indexedSlicesQuery.addEqualsExpression("searchall", ByteBufferUtil.string(bs.toByteBuffer(true)));
indexedSlicesQuery.setColumnFamily(column_family);
indexedSlicesQuery.setStartKey("");
System.out.println(indexedSlicesQuery.toString());
QueryResult<OrderedRows<String, String, String>> res = indexedSlicesQuery.execute();
List<Row<String, String, String>> list = res.get().getList();
for (Row<?, ?, ?> row : list)
{
System.out.println(row.getKey());
}
}

Is this Sql-injection-proof Asp.net code?

Problem: I have a form with text values, and a function that must return a string query based on the values of the text values too.
Solution: I created a SQLCommand query with parameters, then I put the SQLCommand.CommandText to a string and I returned it (to the business logic that is going to handle the query)
Main Question: Is it sql-injection proof?
Code Example:
sQuery = "select * from xy where x like '%#txtNameParameter%'";
SqlCommand cmd = new SqlCommand(sQuery);
cmd.Parameters.Add("#txtNameParameter", SqlDbType.VarChar);
cmd.Parameters["#txtNameParameter"].Value = txtName.Text;
string query = cmd.CommandText;
return query;
Sub question if main question is ok:
Should I put into parameters also values of a radiobutton and dropdownmenu or are they injection-proof?
What you are doing here is injection proof because you are not injecting anything. In fact, your parameter isn't even used (because the only reference to it is inside a string literal so the SQL Parser won't even see where you are attempting to use the parameter because it will treat it as a string literal.)
You may want to change that line of code to:
sQuery = "select * from xy where x like '%'+#txtNameParameter+'%'";
Which would make the SQL look like this:
select * from xy where x like '%'+#txtNameParameter+'%'
Which is just string concatenation in a place where a string is expected in the SQL command anyway.
However, your description of what you are doing with this afterwards possibly blows all that out of the water. I cannot understand why you would want to send just the where clause of the query to the business layer.
Also, the substringed WHERE clause will not contain the data you are putting in the parameter. So you are getting no more benefit that just returning
return "where x like '%#txtNameParameter%'";
The parameter value is lost.

Resources