Conversion failed when converting from string to uniqueidentifier - loading DataTable with ExecuteReader - c#

In attempting to do a SQL query (which returns one string and one uniqueidentifier to columns 0 and 1 respectively) I get "Conversion failed when converting from a character string to uniqueidentifier" in my exceptions log. How can I avoid this? I'm assuming the issue is, the datatables columns are not defined, so it's expecting a string and SQL is trying to convert it. The exception is logged. Surprisingly to me the GUID is stored successfully to da[1]. So my program technically works, however I want to clear this exception and to do that I need to understand why it's happening and how to go about fixing it.
da = new DataTable();
da.Clear();
...
string invoiceStatusSQL = #"select status,invoice_id from invoices where acct_id='" + accountid + "'";
command = new SqlCommand(invoiceStatusSQL, cnn);
da.Load(command.ExecuteReader());

You should always parameterise your SQL queries to help prevent SQL injection and avoid problems like you're facing now. See Why do we always prefer using parameters in SQL statements?.
Use SqlParameter to add the parameters to the SqlCommand.
string invoiceStatusSQL = #"select status, invoice_id from invoices where acct_id = #accountId";
command = new SqlCommand(invoiceStatusSQL, cnn);
SqlParameter idParam = new SqlParameter("#accountId", accountid);
command.Parameters.Add(idParam);
da.Load(command.ExecuteReader());
You can also specify the actual database type when creating the parameter, which will reduce any issues you might have with the framework inferring the type incorrectly (although I don't think that would happen in your case for a Guid/UniqueIdentifier). One way to specify the type is shown below.
var p = new SqlParameter
{
ParameterName = "#accountId",
SqlDbType = SqlDbType.UniqueIdentifier,
Value = accountid
};

Related

When I try to send data from one table to another, I get an error

I'm trying to insert a data into a table that comes from another table - something like this:
decimal saldo = getDbSaldo($#"SELECT Balance FROM clients WHERE Pin='{pin}' AND CardNumber = '{numeroCartao}'");
insertExtrato($#"insert into MoveInfo (CardNumber, Deposit, Saldo, Withdraw, DataHora) Values({numeroCartao}, {deposit}, {saldo}, {withdraw}, getDate())");
The data is getting there:
But when I get it working, I always get this error:
I've been stuck on this for two days.
Now is the time to replace your SQL-injectable code with parameterized queries.
What's happening is that you're not controlling your SQL code. You're munging strings together and executing them as code. The result could be valid SQL code, could be invalid SQL code, could be malicious, could be anything. You're not in control of it so you don't know.
Always add values as parameters. An example would be:
var query = "insert into MoveInfo (CardNumber, Deposit, Saldo, Withdraw, DataHora) Values(#numeroCartao, #deposit, #saldo, #withdraw, getDate())";
var cmd = new SqlCommand() { Connection = cn, CommandText = query };
cmd.Parameters.Add("#numeroCartao", SqlDbType.Int).Value = numeroCartao;
cmd.Parameters.Add("#deposit", SqlDbType.Decimal).Value = deposit;
cmd.Parameters.Add("#saldo", SqlDbType.Decimal).Value = saldo;
cmd.Parameters.Add("#withdraw", SqlDbType.Decimal).Value = withdraw;
cmd.ExecuteNonQuery();
Note that I completely guessed on the SqlDbType values to use here. You'll of course want to use whatever matches your database schema.

Invalid Column Name: "value" - Error Even though it works in another form.

I am stuck at one problem and I just can't solve this.
I get this Error:
Error Message
That's the relevant table
The Code:
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
string query = "UPDATE CAC SET nextMaintainance = #nextMaintainance WHERE department = " + #departmentCB.Text;
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("#nextMaintainance", nextMaintainanceDT.Value);
command.ExecuteNonQuery();
The weird thing I don't understand is that a similar code works just fine without any error in my project:
query = "UPDATE LDV SET received = #received, department = #department WHERE Id =" + #idTxt.Text;
command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("#received", inDT.Value);
command.Parameters.AddWithValue("#department", departmentCb.Text);
command.ExecuteNonQuery();
MessageBox.Show("Lungenautomat wurde aktualisiert");
If relevant, my connection string:
connectionString = ConfigurationManager.ConnectionStrings["SCBA_Manager_0._1.Properties.Settings.SCBAmanagerConnectionString"].ConnectionString;
I really hope you can help me :(
Thank you!
The department column is a text column, so comparing it to a value means the value should be wrapped in quotes.
// This fix is not the recommended approach, see the explanation after this code block
string query = "UPDATE CAC SET nextMaintainance = #nextMaintainance WHERE department = '" + departmentCB.Text + "'";
// ^--------------------------^------ single quote added to wrap the value returned by departmentCB.Text
On the other hand, this error does not occur in your second example, because there you're correctly using the Parameters.AddWithValue() method to add the value for the #department parameter, and because id is a numeric column, so it doesn't require the value wrapped in quotes.
However, while the code shown above does the job, it is not the right way of doing the job. The correct way is to used parameters for all values to be injected into a query. The queries you've shown above are already correctly using parameters for some values (e.g. nextMaintenance in the first query, received and department in the second), but are incorrectly doing string concatenation for other values (e.g. department in the first query, id in the second).
Usage of Parameterized SQL
The benefit of using parameterized SQL is that it automatically takes care of adding quotes, prevents SQL injection, etc.
Therefore, its best to change your first code block to:
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
string query = "UPDATE CAC SET nextMaintainance = #nextMaintainance WHERE department = #department";
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("#department", departmentCb.Text);
command.Parameters.AddWithValue("#nextMaintainance", nextMaintainanceDT.Value);
command.ExecuteNonQuery();
Notice how the string query is a single string without any messy concatenation, and that it contains two parameters #nextMaintenance and #department? And how the values for those parameters are correctly injected using Parameters.AddWithValue() in the following lines?
Your second code block can be similarly improved by using a parameter for the Id column.
query = "UPDATE LDV SET received = #received, department = #department WHERE Id = #Id ";
command.Parameters.AddWithValue("#Id", idTxt.Text);
Further Information
Do read up about SQL injection ( https://technet.microsoft.com/en-us/library/ms161953(v=sql.105).aspx ) to see how using string concatenation like your original code can lead to various security issues, and why parameterized queries are the preferred way of injecting dynamic values into SQL queries.
You can read up more about parameterized queries here: https://msdn.microsoft.com/en-us/library/yy6y35y8(v=vs.110).aspx
In your first example, the WHERE clause evaluates to
WHERE department = Kasseedorf
wheras it should be
WHERE department = 'Kasseedorf'
So the line should be
string query = "UPDATE CAC SET nextMaintainance = #nextMaintainance WHERE department = '" + #departmentCB.Text +"'";
It works in the second example, because id is an integer and doesn't neet quotes.

select query does not work with parameters using Parameters.AddWithValue

The following query in C# doesn't work, but I can't see the problem:
string Getquery = "select * from user_tbl where emp_id=#emp_id and birthdate=#birthdate";
cmdR.Parameters.AddWithValue("#emp_id", userValidate.emp_id);
cmdR.Parameters.AddWithValue("#birthdate", userValidate.birthdate);
OdbcCommand cmdR = new OdbcCommand(Getquery, conn);
OdbcDataReader Reader = cmdR.ExecuteReader();
Reader.HasRows returns no result but when I query it to my database I got data.
I'll assume your code is actually not quite as presented, given that it wouldn't currently compile - you're using cmdR before you declare it.
First, you're trying to use named parameters, and according to the documentation of OdbcCommand.Parameters, that isn't supported:
When CommandType is set to Text, the .NET Framework Data Provider for ODBC does not support passing named parameters to an SQL statement or to a stored procedure called by an OdbcCommand. In either of these cases, use the question mark (?) placeholder.
Additionally, I would personally avoid using AddWithValue anyway - I would use something like:
string sql = "select * from user_tbl where emp_id = ? and birthdate = ?";
using (var connection = new OdbcConnection(...))
{
connection.Open();
using (var command = new OdbcCommand(sql, connection))
{
command.Parameters.Add("#emp_id", OdbcType.Int).Value = userValidate.EmployeeId;
command.Parameters.Add("#birthdate", OdbcType.Date).Value = userValidate.BirthDate;
using (var reader = command.ExecuteReader())
{
// Use the reader here
}
}
}
This example uses names following .NET naming conventions, and demonstrates properly disposing of resources... as well as fixing the parameter issue.
I do think it's slightly unfortunate that you have to provide a name for the parameter when adding it to the command even though you can't use it in the query, but such is life.
Use like this:
string Getquery = "select * from user_tbl where emp_id=? and birthdate=?";
cmdR.Parameters.AddWithValue("#emp_id", userValidate.emp_id);
cmdR.Parameters.AddWithValue("#birthdate", userValidate.birthdate);
OdbcCommand cmdR = new OdbcCommand(Getquery, conn);
OdbcDataReader Reader = cmdR.ExecuteReader();
while(Reader.Read())
{
//Do something;
}
I know this thread is old, but I wanted to share my solution for anyone else coming up on this.
I was having issues with the typical method that Jon posted. I have used it before, but for some reason with this new string I had it was not wanting to actually place the parameter correctly and was causing the reader to not work.
I ended up doing something like this instead, since in the end we are just replacing parts of a string.
string sql = "select * from user_tbl where emp_id = "+ var1 +" and birthdate = "+
var2""
OdbcCommand command = new OdbcCommand(sql);
This was easier for me to get to work. Be warned though, I am not sure if it has any specific drawbacks when compare to using the command parameter method.

Issue with SqlCommand Parameters

When I execute the following query in SSMS I get the expected result i.e. '1'
SELECT TSID
FROM tblTimesheets
WHERE TSUser = 'PJW' AND TSDate = '2012-01-18';
However, when the SqlCommand is produced by the code in my application the ExecuteScalar fails (it simply causes the method to exit with no error message).
public int GetID(string paramUser, DateTime paramDate)
{
string strSql = "SELECT TSID " +
"FROM tblTimesheets " +
"WHERE TSUser = #TSUser AND TSDate = #TSDate;";
string strConnection = BuildConnectionString();
SqlConnection linkToDB = new SqlConnection(strConnection);
linkToDB.Open();
SqlCommand sqlCom = new SqlCommand(strSql, linkToDB);
sqlCom.Parameters.Add("#TSUser", SqlDbType.Text);
sqlCom.Parameters.Add("#TSDate", SqlDbType.Date);
sqlCom.Parameters["#TSUser"].Value = paramUser;
sqlCom.Parameters["#TSDate"].Value = paramDate;
int intResult = (Int32)sqlCom.ExecuteScalar();
linkToDB.Close();
return intResult;
}
I've stepped through the code and can confirm the parameters are PJW and 2012-01-18 as required, but the ExecuteScalar returns any data, which I know should be there based on my comparable query in SSMS.
Please assist.
Instead of SqlDbType.Text try any of the following, depending on the type of the column:
SqlDbType.VarChar
SqlDbType.NVarChar
SqlDbType.NText
SqlDbType.NChar
SqlDbType.Char
When the parameter is of DB type date, it is a good practice to defensively strip the time part on setting the parameter, like this:
sqlCom.Parameters.Add("#TSDate", SqlDbType.Date);
sqlCom.Parameters["#TSDate"].Value = paramDate.Date;
Please let me know if this does not help, and I'll remove my answer.
You say the ExecuteScalar fails with no error message. Wrap your code in a try-catch block to make sure any exceptions that ExecuteScalar() might be throwing are caught.
Other than that try and do as others have suggested and view the SQL produced using SQL Profiler, then run that SQL in SSMS to compare results.
SELECT TSID
FROM tblTimesheets
WHERE TSUser = 'PJW' AND TSDate = '2012-01-18';
Here U r passing the exact date as parameter
Where as while passing the parameter in to the stored procedure you are passing
"DateTime paramDate"
A date time variable
May be you need to parse to exact date format as supported by the stored procedure
i.e you need to format the paramDate variable to 'YYYY-mm-DD'
I am not sure.. Try it.. and reply if it helps or not !

Unicode SQL Query W/ Parameter instead N Prefix

I have an insert query to execute from within a C# against a SQL Server database.
The column I am inserting to is of type nvarchar.
the data I am inserting to that column is non-english.
Is it sufficient for me to use AddWithValue in order to pass the non-english data to the server? like this example:
string dogName = "עברית";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand("INSERT INTO Dogs1(Name) VALUES #Name", connection))
{
command.Parameters.AddWithValue("Name", dogName);
command.ExecuteNonQuery();
}
}
Or must I use the N prefix to declare it unicode? like it says so here.
If I am understanding the question correctly, you can explicitly set the SqlCommand parameter to be a specific data type. You will be able to set it to be nvarchar as shown by the following link: http://msdn.microsoft.com/en-us/library/yy6y35y8.aspx
This below code snippet is taken directly from MSDN:
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "#CategoryName";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = categoryName;
This uses an explicitly created SqlParameter instance, but it is the same idea by indexing the SqlParameterCollection of the SqlCommand instance.
I believe the link at the bottom is only really talking about values within SQL itself.
As far as I'm aware, the code you've got should be absolutely fine - otherwise there'd be no way of specifying Unicode text.
Of course, it's probably worth validating this - but I'd be very surprised if it didn't work.

Categories

Resources