C# sql command parameters not being used? - c#

SqlCommand command = new SqlCommand("UPDATE qcCheckList SET reviewed = #0, errorLevel = #1, comment = #2 WHERE guid = #3 and itemId = #4", connection);
command.Parameters.AddWithValue("0", cli.reviewed.Checked);
int errorLevel = 0;
if (cli.error.Text == "Level 1")
errorLevel = 1;
else if (cli.error.Text == "Level 2")
errorLevel = 2;
else if (cli.error.Text == "Level 3")
errorLevel = 3;
command.Parameters.AddWithValue("1", errorLevel);
command.Parameters.AddWithValue("2", cli.comments.Text);
command.Parameters.AddWithValue("3", guid);
command.Parameters.AddWithValue("4", cli.itemId);
command.ExecuteNonQuery();
Console.WriteLine(command.CommandText);
When i run this code it doesn't look like my sql command's parameters are being replaced by their actual values. I want to be able to see their values when the command is compiled so i can see if the correct command is being sent. Any ideas?

Answer is based on my assumption that you are expecting the query statement (string) to change. That assumption is based on your wording as well as the last sentence in your code statement.
Console.WriteLine(command.CommandText);
The query text is not altered, ie. the parameters in the query text are not replaced with the assigned parameter values. The parameters, and their values, are sent with the query text to the DBMS for execution. In Sql Server you can see this if you were to profile the Sql Server Instance using Profiler.
As a side note I do not recommend you use AddWithValue. See also Can we stop using AddWithValue() already?. Instead just use Add. Also you should give meaningful names to your parameters, like "#errorLevel", when you are able to, it makes debugging easier.
command.Parameters.Add("#errorLevel", SqlDbType.Int).Value = errorLevel;
It is not necessary to prefix the parameter names with "#" when calling Add as it will be done for by the method if you did not. It is considered good practice though but that is a matter of opinion.

When you are assigning value to the parameters, command string will not change. To see actual values of the parameters you can get values after they are being assigned
foreach (SqlParameter item in command.Parameters)
{
Console.WriteLine(item.ParameterName + "=" + item.Value);
}
This will display actual values

dont use # numbers, but named.. such as #parmReview, #parmError, etc... then the NAMED values are in your
command.Parameters.AddWithValue( "parmReview", cli.reviewed.Checked)
command.Parameters.AddWithValue("parmError", errorLevel);
etc.

Related

Update command with parameters gives "Data type mismatch in criteria expression"

I have the following code:
/*
// it works
cmd_oper = "UPDATE [Model Elements] SET [Record Status] = \"Disabled\" WHERE [Index] = #db_idx";
/*/
// it doesn't work
cmd_oper = "UPDATE [Model Elements] SET [Record Status] = #stat WHERE [Index] = #db_idx";
//*/
using( OleDbCommand cmd = new OleDbCommand( cmd_oper, svr_conn ) )
{
cmd.Parameters.Add( "#db_idx", OleDbType.Integer ).Value = 2;
//cmd.Parameters.Add( "#stat", OleDbType.VarChar ).Value = "Disabled";
cmd.Parameters.AddWithValue( "#stat", "Disabled" );
cmd.ExecuteNonQuery();
}
With the second variant of cmd_oper (the one not commented in the beginning of the code) I get "Data type mismatch in criteria expression". The other one works. The type of Record Status column is set in database as Short Text. I know there are many posts related to this error on StackOverflow but I couldn't find an exact fit. Thanks.
The fine manual, https://msdn.microsoft.com/en-us/library/system.data.oledb.oledbcommand.parameters(v=vs.110).aspx has the following to say about parameters
The OLE DB .NET Provider does not support named parameters for passing
parameters to an SQL statement or a stored procedure called by an
OleDbCommand when CommandType is set to Text. In this case, the
question mark (?) placeholder must be used. For example:
SELECT * FROM Customers WHERE CustomerID = ?
Therefore, the order in which OleDbParameter objects are added to the
OleDbParameterCollection must directly correspond to the position of
the question mark placeholder for the parameter in the command text.
Ergo, I think you need your code to be like:
cmd_oper = "UPDATE [Model Elements] SET [Record Status] = ? WHERE [Index] = ?";
using( OleDbCommand cmd = new OleDbCommand( cmd_oper, svr_conn ) )
{
cmd.Parameters.AddWithValue( "anything-name-doesnt-matter", "Disabled" );
cmd.Parameters.Add( "its-position-that-matters", OleDbType.Integer ).Value = 2;
cmd.ExecuteNonQuery();
}
For what it's worth, you should probably name your parameters sensibly (I named them silly above to demonstrate that the name is irrelevant) because the idea is that once prepared, you can execute a statement many times just changing the parameters:
cmd.Parameters["its-position-that-matters"].Value = 3;
cmd.ExecuteNonQuery();
cmd.Parameters["its-position-that-matters"].Value = 4;
cmd.ExecuteNonQuery();
cmd.Parameters["its-position-that-matters"].Value = 5;
cmd.ExecuteNonQuery();
cmd.Parameters["its-position-that-matters"].Value = 6;
cmd.ExecuteNonQuery();
Here i've run the update for index values 3, 4, 5 and 6 too, just by changing the parameter value and re-running. It would hence have been better of me to choose a sensible name for the "index" parameter, to make the code more readable
Steve, in his comment, has noted he believes that you can put named parameters in the query, but the names are ignored (they're essentially treated as ? marks anyway) so you'll still need to add the parameter values in the same order as the placeholders appear. If you have repeated a placeholder in a query, you'll have to repeat-add it to the parameters collection. I've no comment on the accuracy of steve's assertion; I've always used ?
Ultimately, this is all good evidence that really you should get into learning to use a data access library like Entity Framework, and stop writing SQL strings in your button click event handlers - it's not a good way to code. If you'd used EF from the outset, you'd never even have hit this problem. Good on you for using parameterised queries though. Now go check out EF and leave this '90s donkey-way of doing data access behind :)

How do i insert html into my table?

I want to save formatted text into a table, and i use this nice rich text editor that outputs HTML. When I run it i get:
There was an error parsing the query. [ Token line number = 1,Token
line offset = 31,Token in error = < ]
My command looks like:
new SqlCeCommand("UPDATE Bio SET text = " + form["textbox"].Replace("\"", """) + " WHERE id = " + ViewBag.Id, conn)
But I guess it does not like <>, what do I need to replace? Do the same with the quote as with the <>? Any function that escapes it all?
See here for an example of passing the text you want to insert as a parameter:
http://msdn.microsoft.com/en-us/library/system.data.sqlserverce.sqlcecommand.parameters(v=vs.100).aspx
As recommended by MattD - here is example code. Note that I did not actually run this, if there is a syntax issue, leave a note and I'll fix it. This should get you 99% of the way in any case.
Also note: it is ALWAYS a good idea to use parameters this way, rather than appending literal text into a sql query. This eliminates the possibility of a SQL injection error or hack, where someone might maliciously enter text that finishes your SQL and then adds their own SQL that will also get executed.
SqlCeCommand command = new SqlCeCommand("UPDATE Bio SET text = #htmlText WHERE id = #id", conn);
SqlCeParameter param;
// NOTE:
// For optimal performance, make sure you always set the parameter
// type and the maximum size - this is especially important for non-fixed
// types such as NVARCHAR or NTEXT; In case of named parameters,
// SqlCeParameter instances do not need to be added to the collection
// in the order specified in the query; If however you use ? as parameter
// specifiers, then you do need to add the parameters in the correct order
//
param = new SqlCeParameter("#id", SqlDbType.Int);
command.Parameters.Add(param);
param = new SqlCeParameter("#htmlText", SqlDbType.NVarChar, -1);
command.Prepare();
//Set the values and the length of the string parameter
command.Parameters[0].Value = ViewBag.Id;
command.Parameters[1].Value = form["textbox"];
command.Parameters[1].Size = form["textbox"].Length;
// Execute the SQL statement
//
command.ExecuteNonQuery();

Update command error

I want to update a row by code in my form. Maybe some columns are null. So while command is
executing, an error will rise and say Incorrect syntax near the keyword 'where':
SqlCommand Update = new SqlCommand("Update Table_065_Turn SET Column02=" + Row["Column48"] + " , Column15= " + Row["Column15"].ToString() +
" where ColumnId=" + StatusTable.Rows[0]["ColumnId"], Con);
Update.ExecuteNonQuery();
I know this error will be displayed because Row["Column15"] is null.
How can I check if the column in datarow is null; of course without any extra variable or commands before Update command.
I mean check columns exactly in update command.
I would recommend using SqlParameters, also SqlCommand implements IDisposable so you should wrap it up in a using statement e.g.
using (SqlCommand update = new SqlCommand("Update Table_065_Turn SET Column02=#Col2, Column15=#Col15 where ColumnId=#ColId", con))
{
update.Parameters.AddWithValue("#Col2", Row["Column48"]);
update.Parameters.AddWithValue("#Col15", Row["Column15"]);
update.Parameters.AddWithValue("#ColId", StatusTable.Rows[0]["ColumnId"]);
update.ExecuteNonQuery();
}
Also you might be better actually validating the fields before you execute the query unless null is a valid column value.
I suspect you have to "replace" .net null with database keyword NULL, e.g.
string sql = "Column15 = " + (row[15] == null ? "NULL" : row[15].ToString()) in your case, but the much better way is to use Parameters as written by James, also keep in mind someone could provide hamful strings to your query:
row[15] = ";DROP DATABASE; --" would be enough in your case to cause all your data to be lost ;) (see "SQL injection" on your favorite search engine
you could use
var value = "" + Row["columnname"] ;
so ,you do not need to check the object is null
it is safe..
You could do like this:
string filterString;
if (StatusTable.Rows[0]["ColumnId"]!=System.DBNull.Value)
filterString= #" WHERE ColumnID= StatusTable.Rows[0]["ColumnId"]";//I assume the value returned is a string
else
filterString="";
And then you can just append the filterString variable to your SQLCommand string.

How to read the output variable from .net c#?

Does anyone know how can I read the output variable from .net c#?
Example:
If I have the following stored proc which will return the output variables (#customer_id, #customer_name, #customer_address, #customer_age) instead of the select variable, how can I read the output variable with the following?
mySqlCommand.CommandText = "EXEC app_customers #name=" + sName.Text;
mySqlConnection.Open();
SqlDataReader mySqlDataReader = mySqlCommand.ExecuteReader();
while (mySqlDataReader.Read())
{
}
When the result is a single value (or if you're just interested in the first value in the first column), use the method ExecuteScalar.
It returns an object, simply cast it to the expected type.
int id = (int)mySqlCommand.ExecuteScalar();
Note: the way you're invoking a procedure is not the normal way to do it. Set the command to reference the stored procedure, then add appropriate parameters to the command.Parameters collection. Invoking the procedure using "exec ..." is not a best practice and may even leave you vulnerable. If you need more info on executing such a call, start here.
Edit:
If it is truly an output parameter you need to capture (I believe I misread your question), then the above paragraph is even more applicable. Consider this approach:
mySqlCommand.CommandText = "app_customers";
mySqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
mySqlCommand.Parameters.AddWithValue("#name", theValue);
var customerIdParam = mySqlCommand.Parameters.Add("#customer_id", System.Data.SqlDbType.Int);
customerIdParam.Direction = System.Data.ParameterDirection.Output;
// add more parameters, setting direction as appropriate
mySqlCommand.ExecuteNonQuery();
int customerId = (int)customerIdParam.Value;
// read additional outputs

Why are parameters slower than literal values in a where clause?

Situation: c#, sql 2000
I have a table, lets call it 'mytable' with 30 million rows.
The primary key is made up of fields A and B:
A char(16)
B smallint(2)
When i do a search like this, it runs really slowly (eg it does a full tablescan)
string a="a";
int b=1;
string sql = "select * from table(nolock) where a=#a and b=#b";
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("#a", a);
cmd.Parameters.AddWithValue("#b", b);
using (SqlDataReader rdr = cmd.ExecuteReader()) {...}
}
Change it to this however, and it runs really quick (eg it hits the index):
string where =
String.Format("a='{0}' and b={1}", a, b);
string sql = "select * from table(nolock) where " + where;
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
using (SqlDataReader rdr = cmd.ExecuteReader()) {...}
}
What on earth is going on? Seems strange to me.
Do data types of parameter and column match? They don't it appears so datatype precedence applies
The column is smallint, but you send int. The column will be converted to int because it has a higher precedence. So it won't use an index.
Does it make any difference if you declare the b variable to be a short instead of int?
Does it make any difference if you explicitly specify the types of the parameters?
Does it make any difference if you use "where a=#a and b=#b" instead of the comma form?
I agree this does sound odd, and I wouldn't really expect any of these changes to help, but it's probably worth a try.
You may tell SQL Server which index to use for a query. Use the WITH (INDEX = INDEX_ID) option where INDEX_ID is the ID of the index.
Get index ID's with:
SELECT i.indid, i.name FROM sysindexes i
INNER JOIN sysobjects o ON o.ID = i.id
WHERE o.Name = 'table'
So try then:
SELECT * FROM table(NOLOCK) WITH (INDEX = 1) WHERE a=#a and b=#b
As #gbn said, setting the data type should make it easy for you.
string where =
String.Format("a='{0}' and b={1}", a, b);
In the example above, you are telling SQL to treat parameter a as char.
Whereas, in other example it will be treated as a varchar.
Use SQL profiler to see what is the SQL that gets executed in both the cases. That should clear it for you.
In the first case you are adding SqlParameter classes to the command. When the command is executed it is most likely generating DECLARE statements with the wrong data type. (You can verify this with a SQL trace.) If this is the case, the optimizer cannot select the correct index and falls back to a table scan.
If you use a stored proc instead, you would be forcing the parameters into the data types you declare. However, you can still do this from code if you specify the SqlDbType on the parameters.

Categories

Resources