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.
Related
I'm creating a basic customer inventory application, and when converting the code from using SQL Server to using MS Access (which I'm quite a bit less versed in), I ran into a "Data type mismatch" error when trying to do a basic insert.
I've looked into several similar questions here, and double checked the msdn syntax guide, but I can't find a reason why the script I've written would generate that error. I changed my code several times to try and ensure proper data type (ending up with what I have below with explicit typing and adding the value later). I've actually even taken the string and pasted it into MS Access (sans white space and double quotes), and it seems to work just fine with the values given. At this point, I'm really and truly stumped, and I'm wondering if it might just be a quirk with the Oledb adapter? Any help would be appreciated. Thanks.
// SQL query defined elsewhere:
public static readonly string sqlAddCustomerNotes = "INSERT INTO CustomerNotes (Customer_ID, Notes, NotesDate) "
+ "VALUES(#Customer_ID, #Notes, #NotesDate);";
// end sql query
// data access function
public static void addNotes(int customerID, string notes, DateTime notesDate)
{
string query = Scripts.sqlAddCustomerNotes;
using (
OleDbCommand dbCommand = new OleDbCommand()
{
Connection = new OleDbConnection(ConnectionAccess.connString),
CommandType = CommandType.Text,
CommandText = query,
Parameters =
{
new OleDbParameter("#Customer_ID", OleDbType.Integer),
new OleDbParameter("#Notes", OleDbType.LongVarChar),
new OleDbParameter("#NotesDate", OleDbType.DBTimeStamp)
}
}) // end using parenthetical
{ // begin using scope
dbCommand.Parameters[0].Value = customerID;
dbCommand.Parameters[1].Value = notes;
dbCommand.Parameters[2].Value = notesDate;
foreach (OleDbParameter param in dbCommand.Parameters)
{ // replace ambiguous null values with explicit DBNulls.
if (param.Value == null)
{
param.Value = DBNull.Value;
}
}
dbCommand.Connection.Open();
int rowsAffected = dbCommand.ExecuteNonQuery();
dbCommand.Connection.Close();
Console.WriteLine($"Rows affected: {rowsAffected}");
}
} // end addCustomerNotes
/*
table "CustomerNotes" has the following columns:datatypes
CustomerNotes_ID: AutoNumber
Customer_ID: Number
Notes: Memo
NotesDate: Date/Time
CreateDate: Date/Time
test case (in code) was:
#Customer_ID = 5
#Notes = "customer might change last name to simpson."
#NotesDate = {6/26/2019 12:05:39 PM}
*/
It probably is a date, not a timestamp:
new OleDbParameter("#NotesDate", OleDbType.DBDate)
Considering June7's comment about delimiters, it seems the issue lies in some issue inherent to the OleDbParameter type. In SQL Server terms, I do want DateTime (not Date), but representing it as a DBTimeStamp seems to make it unrecognizable by Access.
For the time being, I've sent the date as a VarChar and allowed Access to convert it however its internal engine sees fit. It feels/seems wrong, but it does, in fact, solve the problem.
Parameters =
{
new OleDbParameter("#Customer_ID", OleDbType.Integer),
new OleDbParameter("#Notes", OleDbType.LongVarChar),
new OleDbParameter("#NotesDate", OleDbType.VarChar)
}
EDIT: Just saw June7's latest comment, and there was in fact, an answer in another thread. OleDbType.DBDate doesn't do what I want, but OleDbType.Date does.
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.
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.
I am having trouble with an MySql query.
string strSql = "select SQL_CALC_FOUND_ROWS *, pv.* from products pv WHERE pv.name = 'Teddy Bear';";
strSql += "SET #resultCount = FOUND_ROWS();"
MySqlParameter parm = new MySqlParameter("#resultCount",MySqlDbType.Int32)
parm.Direction = ParameterDirection.Output;
var result = ObjectContext.ExecuteStoreQuery<Product>(strSql,parm);
return result;
The Error returned is
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL = FOUND_ROWS()' at line 1
How do I get #resultCount to return the total record count
When creating the parameter I think you need to specify the name without #.
Also, you'll want to specify the parameter direction; I think that by default it's input only, meaning you need to provide a value that will be inserted into the command; what you want is output. You can specify the direction through some overloads when creating the parameter or by setting a property - don't know if the syntax differs from other providers as I haven't worked with the MySql one in quite some time, but it should be:
parm.Direction = ParameterDirection.Output;
string queryStr = "select max(patient_history_date_bio) " +
"as med_date, medication_name from biological where " +
"(patient_id = " + patientID.patient_id + ") " +
"group by medication_name;";
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(queryStr, conn))
{
conn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
int count = 0;
while (rdr.Read())
{
MessageBox.Show("test");
med.medication_date[count] = new DateTime();
med.medication_date[count] = DateTime.Parse(rdr["med_date"].
ToString());
MessageBox.Show("test2");
med.medication_name[count] = rdr["medication_name"].ToString();
count++;
}
}
conn.Close();
}
so i'm trying to read this sql statement. "test" message box displays, but not "test2". I tried running the sql statement in VS by itself (in the server explorer), and the sql statement works. it gives me what i want. but somehow, the code doesn't work... does anyone see why?
Assuming patient_id is some sort of integer (or is it a Guid), my assumption is that the current culture of your program is causing the ToString method call on int to be formatted in a way that is returning something that the parser can't parse (e.g. "1,234,567").
Generally, the way you are executing this statement is not a best-practice. While you might not be susceptible to injection attacks if the id is indeed an int (you are most definitely open to them if it's a string), you generally want to parameterize the queries.
The reason for this is not only to protect against injection attacks, but because it will properly format the parameter in the query string according to the type.
Another thing to point out about your code is how you are retrieving the values from the reader. You are effectively calling ToString on the DateTime instance, then calling Parse on the string to get a DateTime back.
This effectively burns cycles. All you need to do is cast (unbox in the case of value types) the value back.
So where you have:
med.medication_date[count] = DateTime.Parse(rdr["med_date"].
ToString());
You should have:
med.medication_date[count] = (DateTime) rdr["med_date"];
All that being said, as to why the second message box is not showing, my first guess is that you are executing this in an event handler in a Windows Forms application, and that an exception is being thrown.
I think that what you will find is that if medication_date is an array, then it hasn't been initialized and you are getting a NullReferenceException or something about the array index being out of bounds.
What is med.medication_date?
If it is an array, maybe it hasn't been initialized yet.
If it is a list, you should assign to it using med.medication_date.Add(value);
Alternatively, as everyone else is saying, the date time conversion may be at fault. Try replacing
MessageBox.Show("test");
With
MessageBox.Show(rdr["med_date"].ToString());
you should direct your debug stuff to the output window...it's muche easier to follow the flow.
system.diagnostics.debug.writeline(rdr["med_date"].ToString());
Without more info, it looks like the line
med.medication_date[count] = DateTime.Parse(rdr["med_date"].ToString());
throws an exception due to an unrecognised date, and the exception is being swallowed by a handler higher up.