Simpler way of writing statement with StringBuilder - c#

I am attempting to convert query below which executes the update statement based on the boolean value. i am adding the warehouse based on an if statement, but i am not quiet sure how to write this with StringBuilder. I am quiet new to C#.
string query = value ? "UPDATE Warehouse SET usen = 'T' WHERE warehouse='01'" : "UPDATE Warehouse SET use = 'F' WHERE warehouse='01'";
I attempted the following:
StringBuilder query = new StringBuilder();
query.Append(value ? "UPDATE Warehouse SET usen = 'T' WHERE warehouse='");
if (warehouse.Equals("T"))
query.Append(TWarehouse + "'");
else if (warehouse.Equals("V"))
query.Append(VWarehouse + "'");
query.Append(: "UPDATE Warehouse SET usen = 'F' WHERE warehouse);
This did not work. Clearly I am doing something wrong. Can anyone help me figure this out.

There are better ways than constructing a query in a string and executing it against the database.
As #AlexeiLevenkov suggest, you should use parameterized queries. See How to Execute a Parameterized Query.
Also the StringBuilder is recommended for long strings and more complex situations.
From StringBuilder documentation:
"Although the StringBuilder class generally offers better performance
than the String class, you should not automatically replace String
with StringBuilder whenever you want to manipulate strings.
Performance depends on the size of the string, the amount of memory to
be allocated for the new string, the system on which your app is
executing, and the type of operation. You should be prepared to test
your app to determine whether StringBuilder actually offers a
significant performance improvement. "
In your case you can use string.Format and have a more readable code, like:
string format = "UPDATE Warehouse SET use = '{0}' WHERE warehouse='01'";
string query = string.Format(format, value ? "T" : "F");

query.Append(value ? "UPDATE Warehouse SET usen = 'T' WHERE warehouse='");
This isn't valid C#.
https://msdn.microsoft.com/en-us/library/ty67wk28.aspx
I'd recommend reading up on the conditional operator. Look at the first line in your question (I've reformatted it a bit)
string query = value
? "UPDATE Warehouse SET usen = 'T' WHERE warehouse='01'"
: "UPDATE Warehouse SET use = 'F' WHERE warehouse='01'";
What this does is conditionally assign a value to the query variable. It'll assign "UPDATE Warehouse SET usen = 'T' WHERE warehouse='01'" if value == true, or it'll assign "UPDATE Warehouse SET use = 'F' WHERE warehouse='01'" if value == false.

Is this what you try to do?
StringBuilder query = new StringBuilder();
query.Append("UPDATE Warehouse SET usen = '");
query.Append(value? "T" : "F");
query.Append("' WHERE warehouse='");
if(warehouse.Equals("T"))
{
query.Append(TWarehouse);
}
else if(warehouse.Equals("V"))
{
query.Append(VWarehouse);
}
else
{
query.Append("YourDefaultValue");
}
query.Append("'");
As Carlos said, your way of writing the code is wrong.

Related

Unexpected token when creating a string expression?

I have the following code:
public void UpdateCardSetColumn(CARD cardColumn, bool value, string cardId)
{
string strValue = value ? "1" : "0";
sql = $"UPDATE Card SET {cardColumn.Text()} = {strValue}​ WHERE CardGuid = '{​cardId}​'";
RunExecute(db2, sql);
}
There is an error here '{cardId
And it tells me
Invalid Expression term "
You need to be aware that this kind of string concatenation is avoided and it is open to SQL Injection attack, you should always use parameterized queries to avoid SQL Injection and also to get rid of errors, something like this:
sql = "UPDATE Card SET cardColumn = #strValue​ WHERE CardGuid = #​cardId";
yourSqlCommand.Parameters.AddWithValue("#strValue​ ", cardColumn.Text);
yourSqlCommand.Parameters.AddWithValue("#​cardId", ​cardId);
Although specifying the type directly and using the Value property is better than AddWithValue:
yourSqlCommand.Parameters.Add("#​cardId", SqlDbType.VarChar).Value = ​cardId;
Read more here: https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
The problem was fixed when the line was entered again. There must have been some non-ascii character in the text as it's working good now.

Query return on C#/mysql

I have in my class "fattura" this
public string sommaFattura(String costo)
{
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
//Need the command for take the result
conn.closeConnection();
}
What is the command for take the result of Sum query?
I want use this command, insert in a variable. Can you correct me?
I think the command you want is
command.ExecuteScalar();
However, note, Execute Scalar is intended that the result will return a single row, single column which your query does without regard to your parameter. However your query does not specifically make sense either..
Now your query itself. You have an explicit prezzo which would imply an existing column name and not that of a parameter. It would have to a numeric field for obvious reasons to sum it.
Now you also have an expected string coming in via "costo" parameter to the function call. If your intent is to have the incoming string be representative of a known column of the table, this is not going to work for you. You would have to build the SQL command with that explicit column name, or build doing dynamic-sql, but that would really be too much.
The concern with building a SQL statement with string parameters is you would be open to SQL-injection, especially if web-based. If your incoming string is coming from a controlled source, such as you are presenting a list of columns to a user and they can only pick one such column. Or, you have buttons on a screen asking for a sum of a certain thing, and YOU control that column name you would be in a better condition, but still be cautious passing parameter to build out SQL.
Say for example your table has numeric fields of qtySold and dollarSales. You want either the sum of either of these columns and are passing one of these respective strings into the function such as
var qtySoldAnswer = sommaFattura( "qtySold" );
or
var dollarSalesAnswer = sommaFattura( "dollarSales" );
Then your function would be CLOSER to...
public string sommaFattura(String costo)
{
MySqlCommand command = new MySqlCommand();
command.CommandText = "SELECT SUM(" + costo + ") FROM fatturetemp";
command.Connection = conn.getConnection();
conn.openConnection();
var answer = command.ExecuteScalar();
conn.closeConnection();
// I would put a breakpoint in here to see the results.
// you can then format the answer such as decimal point, etc.
return answer.ToString();
}
AGAIN, ONLY if YOU have control of the column name you are trying to send in. Someone could do sql-injection and do a lot of damage. I would only do with heavily controlled consideration and explicitly validating the columns you WOULD allow, and if so, set your variable at that point. Don't allow for any more or less than the column name. No special characters, quotes, comments, sql-terminator and new statement...
But hopefully this clarifies what I THINK you are trying to accomplish.

SQL query formation dynamically, using string.format

I have a serious problem of formatting queries, it may result in SQL injection too, I saw some similar qstns, but not sure how could i use it in C# as I am new to it. I use c#,Odbc command
I have 3 strings like
qry ="select description from TableA" , qryOrder = " order by description" , qryAppend = " where ID = '{0}' order by description\", _selectedPlantID" provided _selectedId is another variable, Now I want to use these variables to form diff queries at different scenarios, for eg, qry + qry order , or qry + qryAppend.
Since _selectedPlantId is also needed, I use string.Format as :
_cmd.CommandText = "string.Format(\"" + qry + qryAppend + ")";
But its not working. any solution ?
Error is SQL syntax error with quotes
thanks in advance !!
Simply put, this should make it work. You'll need two variables (bool), I'll explain later why:
var shouldOrder = true;
var shouldAppend = true;
_cmd.CommandText = String.Format(
"{0} {1} {2}",
qry,
shouldOrder ? qryOrder : String.Empty,
shouldAppend ? qryAppend : String.Empty
);
These two variables (shouldOrder and shouldAppend) will help you with the "diff queries at different scenarios" as you've said.
Providing these variables with true or false will change what text goes into the String.Format and will change query accordingly.
So, if you use shouldOrder = false; the query command won't get the order part. Setting shouldAppend = false; will avoid including the extra part (append) into the SQL command.
Now, be careful!
This won't solve your SQL injection problem. I've just shown a quick fix.
To avoid SQL injections, you'll have to change your SQL command and you cannot use String.Format anymore.
To understand how to do that, take a look into DGibbs comment.

Best way to build a query with condition on code-behind?

How to make this code properly? I am not satisfied with this code, I'm lost.
I give you a simple example but the query is more complexe.
Thanks in advance.
string aValue;
string queryA;
string queryB;
string finalQuery;
string queryA = #"SELECT column1 FROM table1 WHERE column1=";
queryA += aValue;
string queryB = #"SELECT column1, column2,"
if (aValue == "all"){
queryB += #"column3";
}
queryB += #"FROM table1 WHERE column1=";
queryB += #"'" +aValue+ "'";
private void exportExcel(){
// change the value with a dropdownlist
if (ddlType.selectedIndex(1))
aValue = "typeA";
else if(ddlType.selectedIndex(2))
aValue = "typeB";
else
aValue = "all";
// select the query
if (aValue == "typeA")
finalQuery = queryA;
else if (aValue == "typeB")
finalQuery = queryB;
ExecQUery(finalQuery);
}
In both Java and C# (and pretty much any other platform) you should definitely not include the values directly in the SQL. That's opening up the way to SQL injection attacks, and also makes dealing with formatting for dates, times and numbers tricky.
Instead, you should use parameterized SQL, specifying the values in the parameters. How you do that varies between Java and C#, but the principle is the same.
Another approach on both platforms is to use an ORM of some description rather than building queries by hand. For example, in .NET you might want to use a LINQ provider of some description, and in Java you might want to use something like Hibernate. Either way you get to express your queries at a higher level of abstraction than just the raw SQL.
It's hard to give much more concrete advice without knowing what platform you're really using (or database) and without a real query to look at.
One small change you can do is set value attribute of dropdownlist to typeA,TypeB, etc.. and get rid of the initial if conditions and variables.
eg:
if(ddlType.selectedValue.toString()=="typeA")
finalQuery = queryA;
if(ddlType.selectedValue.toString()=="typeB")
finalQuery = queryB;
I usually load it from a resource file. This gives you some freedom to change the queries (this in case you don't need to generate it dynamically with if blocks). In source code I use formatting ending my line with a comment line in order to avoid my IDE to concatenate or put it all in one like like:
String sql = "select " + //
" * " + //
"from "+ //
" employee " + //
"where " + //
" salary > :minSal " + //
" and startDate > :minStartDate";
And in case of conditional part I just add it with a if block. But for where statements I just add one default "1=1" in order to proceed with additional limitations, so if there is no additional limitations the query will still be valid. Suppose both where statements in the SQL bellow were added conditionally:
String sql = "select " + //
" * " + //
"from "+ //
" employee " + //
"where 1 = 1 ";
Until here you have your base SQL, valid, that means if not condition is added it will still be valid.
Suppose you will add salary limitation just in case if it is informed:
if (salary != null) {
sql += "and salary > :minSalary";
parameters.put("minSalary", salary);
}
As you can see in the same condition I add a new expression to my SQL and a parameter to a map that will be used later in execute to set the parameters to the query, that avoids you to create a second if statement just to set this parameter.
Another approach that you could take is build the entire SQL and before the execution ask for the prepared statement which parameters it needs as input and provide them. In java you can do it with:
http://download.oracle.com/javase/1.4.2/docs/api/java/sql/PreparedStatement.html#getParameterMetaData%28%29
I know that is not the case but if ORM is used, is common to have Builders for queries and this turns this task much easier, for example in Hibernate you could have something like:
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%")
.addOrder( Order.asc("name") )
.addOrder( Order.desc("age") )
.setMaxResults(50)
.list();
As it is documented at:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/querycriteria.html
That means you could do this:
Criteria c = sess.createCriteria(Cat.class)
.addOrder( Order.asc("name") )
.addOrder( Order.desc("age") )
.setMaxResults(50);
if (name != null) {
c.add( Restrictions.like("name", name);
}
List cats = c.list();

Help with Parameterizing SQL Query for C# with possible null values

I need help with parameterizing this query.
SELECT *
FROM greatTable
WHERE field1 = #field1
AND field2 = #field2
The user should be able to search for any of the 2 fields, and the user also should be able to search if the field2 has null values.
var query = "theQuery";
var cm = new SqlCommand(cn, query);
cm.AddParameter("#field1", "352515");
cm.AddParameter("#field2", DBNull.Value);
// my DataTable here is having 0 records
var dt = GetTable(cm);
[Edit]
What is the best alternative?
Keep CommandText constant so the plan in Sql be reused
WHERE (field2 = #field2 OR #field2 IS NULL)
Change CommandText dynamically based on the values introduced by the user.
WHERE field2 IS NULL
I'm not just thinking in one field, it could be various.
You can use AND (#field2 IS NULL OR field2 = #field2) to make the query return all rows without checking field2 (to allow you to pass DbNull from your code.
The complete query would be something like this:
SELECT *
FROM greatTable
WHERE field1 = #field1
AND (#field2 IS NULL OR field2 = #field2)
Note that when using this method there might be a performance-hit because of indexing. Take a look at this article for details.
A dirty method:
isnull(field2,0) = isnull(#param2,0)
have the isnull something that would never be in the field or param
A good question, but in practice I had no time such problem. If I use AddParameter then I also construct the string for the query in the same code fragment. So if I know, that now I should search for "#field2" equal to NULL I decide whether to construct
string query = "SELECT * " +
"FROM greatTable " +
"WHERE field1 = #field1";
or
string query = "SELECT * " +
"FROM greatTable " +
"WHERE field1 = #field1 AND field2 IS NULL";
and add only one parameter
cm.AddParameter("#field1", "352515");
So I have no time the problem which you describe.
UPDATED: What is the best (or the only correct) way is users input is NULL you should decide based on the context. In the most cases "AND field2 IS NULL" is not needed, but I read your question so, that in your special case the user can explicitly choose not "" (empty string), but a NULL value.

Categories