I have a class SqlGetGroupCutRates which has a
public bool UpdateDefaultTarget(string param1)
method. In this method, I am using the SqlClient.SqlCommand class.
public bool UpdateDefaultTarget(string g1)
{
string myworkCenterCode = Form1.globalWorkCenter;
try
{
string connString = #"Data Source =" + server + "; Initial Catalog =" + redGreenDB + ";Integrated Security=SSPI";
// WHERE CUT_RATE_GROUP = #CUT_RATE_GROUP... WHAT IS #CUT_RATE_GROUP????
string myCommandString = "SELECT TOP 1 Default_Cut_Rate_Per_Hour FROM " + groupCutRateTable + " WHERE " +
"Cut_Rate_Group= #Cut_Rate_Group ORDER BY Record_Date DESC";
// SQL connection using the connString taking us to the redGreenDB
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
// Get the specific default cut rate from groupCutRateTable ("dbo.ABR_Tape_Cvt_Group_Cut_Rates") where Cut_Rate_Group (column)
using (SqlCommand cmd = new SqlCommand(myCommandString, conn))
{
cmd.Parameters.AddWithValue("Cut_Rate_Group", g1);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
defaultFoundInQuery = true;
while (reader.Read())
{
int ordTarget = reader.GetOrdinal("Default_Cut_Rate_Per_Hour");
// Handle potential null database values:
if (!reader.IsDBNull(ordTarget))
{
int ord1 = reader.GetOrdinal("Default_Cut_Rate_Per_Hour");
default_Cut_Rate_Per_Hour = reader.GetDouble(ord1);
}
else
{
default_Cut_Rate_Per_Hour = 0;
}
}
}
// else if no data rows found.
else
{
default_Cut_Rate_Per_Hour = 0;
}
conn.Close();
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Problem getting Group Cut Rates from database: \n" + ex);
}
return defaultFoundInQuery;
}
In my myCommandString variable, you will notice it is set to the value
string myCommandString = "SELECT TOP 1 Default_Cut_Rate_Per_Hour FROM " + groupCutRateTable + " WHERE " +
"Cut_Rate_Group= #Cut_Rate_Group ORDER BY Record_Date DESC";
I am querying the top 1/first Default_Cut_Rate_Per_Hour column value from the groupCutRateTable WHERE the Cut_Rate_Group column value is #Cut_Rate_Group.
My question is... in this query... what is meant by the #Cut_Rate_Group part of the query? Is this just going to return the first Cut_Rate_Group column value? Essentially making this a "static" query that will always return the same value? Or is the syntax of #Cut_Rate_Group seen as dynamic? Meaning #Cut_Rate_Group is assigned a value somewhere in my code?
Apologies, I am very new to this. If you have any docs I could read further into this, I would also appreciate that so I can better understand any answer I may get. Thanks for taking the time to read this.
I am expecting that this syntax would make #Cut_Rate_Group dynamic in the sense that it is almost viewed as a variable that is assigned a value.
The statement
cmd.Parameters.AddWithValue("Cut_Rate_Group", g1)
creates the parameter #Cut_Rate_Group that is referred to in the select statement. Since its value comes from the parameter g1, it will be "dynamic" in that whatever value is passed in g1 will become the value of the parameter #Cut_Rate_Group used in the select statement.
The statement above could have been written
cmd.Parameters.AddWithValue("#Cut_Rate_Group", g1)
If you call UpdateDefaultTarget with the same value of g1, and no records have been deleted from the table, it will return the same record if no new records have a record date less than or equal to that original record.
However, not knowing what you are trying to accomplish, this may not be what you actual want to happen.
#Cut_Rate_Group is a sql paramter (and is dynamic like a variable). Parameterization of sql commands is to safe guard from sql injections.
It's value is added here
cmd.Parameters.AddWithValue("Cut_Rate_Group", g1)
Related
I am currently in a corner and have no idea why the following code will not execute properly and update the database (Access).
newUser = All of the new user's data including their ID
list = Contains a list of GermanResources (class) entries that correspond to the pages checkboxes. Class includes .Name (text value of checkbox) and .Value (checked? 1 or 0)
I want to update the database with the checkbox value of each GermanResource.
IF i replace #acc_Value with the value 1 this code works. It seems to not work with the first parameter in place. Debugging this showed me that everything had the proper values at the proper times and since "1" worked I know the data types are not mismatched.
Note: There were no errors with or without the parameter in place.
I would appreciate any input about this.
This is one of the CommandTexts that are generated:
UPDATE VMS_GRM_GermanResource_Access SET VTOFZN = #acc_Value WHERE UserId = #userId
private bool NewUser_Insert_GermanResourceAccess(OleDbConnection connection, User newUser, List<GermanResource> list)
{
bool result = false;
try
{
foreach (var item in list)
{
string column = item.Name.Replace(" ", "");
string query = #"UPDATE VMS_GRM_GermanResource_Access SET " + column + " = #acc_Value WHERE UserId = #userId";
OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.AddWithValue("#userId", newUser.Id);
command.Parameters.Add(new OleDbParameter("#acc_Value", OleDbType.Integer, 1));
command.Parameters["#acc_Value"].Value = item.Access;
command.ExecuteNonQuery();
}
result = true;
}
catch (OleDbException ex)
{
UADConnection.Close();
MessageBox.Show(ex.ErrorCode.ToString() + ": " + ex.Message);
return result;
}
return result;
}
Use this to prepare sql statement :-
string query = #"UPDATE VMS_GRM_GermanResource_Access SET column_name=" +
#acc_Value + " WHERE UserId = " +#userId+";
#Tetsuya Yamamoto:
OLEDB parameters were not in order according to the query. Swapping them around to match the order in the query set things straight. All good again and thanks for everyone's inputs.
I am making DatabaseManager class for my solution and I am getting the number 0 when I am trying to update the text.
For example : I have now the name michael and I wanted to change it to "michael , mike" so I'll probably use update.
public void AddCrime(CSteamID id, string crime, string time)
{
try
{
MySqlConnection connection = createConnection();
MySqlCommand command = connection.CreateCommand();
crime = "," + crime;
command.CommandText = "update `" + Main.Instance.Configuration.Instance.DatabaseTableName
+ "` set `crime` = crime + ( #crime ) where `steamId` = #steamID; select `crime` from `"
+ Main.Instance.Configuration.Instance.DatabaseTableName
+ "` where `steamId` = #steamID";
command.Parameters.AddWithValue("#steamID", id);
command.Parameters.AddWithValue("#crime", crime);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
AddTime(id, time);
}
catch (Exception ex) { Logger.Log(ex); }
}
How do I call it :
DatabaseManager.AddWanted(player.CSteamID, command[1], command[2]);
Thanks everyone!
yor last sentence in your command is a select statement, NonQuery does not return values, only the number of rows affected. Change it to ExecuteScalar and store the value of the select in a variable.
Second error is the data type of the parameter #steamID. You set the value id, which is declares as CSteamID id... CStreamId is not string, change the AddWithValue
Fixed, I added another method to get crime from table and then changed the void crime string to the current string + the table text.
The error was : Truncated incorrect DOUBLE value.
I am somwhat new to SQL, so I am not sure I am going about this the right way.
I am trying to fetch data from my SQL Server database where I want to find out if checkedin is 1/0, but it needs to search on a specific user and sort after the newest date as well.
What I am trying to do is something like this:
string connectionString = ".....";
SqlConnection cnn = new SqlConnection(connectionString);
SqlCommand checkForInOrOut = new SqlCommand("SELECT CHECKEDIN from timereg ORDER BY TIME DESC LIMIT 1 WHERE UNILOGIN = '" + publiclasses.unilogin + "'", cnn);
So my question, am I doing this right? And how do I fetch the data collected, if everything was handled correctly it should return 1 or 0. Should I use some sort of SqlDataReader? I am doing this in C#/WPF
Thanks
using (SqlDataReader myReader = checkForInOrOut.ExecuteReader())
{
while (myReader.Read())
{
string value = myReader["COLUMN NAME"].ToString();
}
}
This is how you would read data from SQL, but i recommend you looking into Parameters.AddWithValue
There are some errors in your query. First WHERE goes before ORDER BY and LIMIT is an MySql keyword while you are using the Sql Server classes. So you should use TOP value instead.
int checkedIn = 0;
string cmdText = #"SELECT TOP 1 CHECKEDIN from timereg
WHERE UNILOGIN = #unilogin
ORDER BY TIME DESC";
string connectionString = ".....";
using(SqlConnection cnn = new SqlConnection(connectionString))
using(SqlCommand checkForInOrOut = new SqlCommand(cmdText, cnn))
{
cnn.Open();
checkForInOrOut.Parameters.Add("#unilogin", SqlDbType.NVarChar).Value = publiclasses.unilogin;
// You return just one row and one column,
// so the best method to use is ExecuteScalar
object result = checkForInOrOut.ExecuteScalar();
// ExecuteScalar returns null if there is no match for your where condition
if(result != null)
{
MessageBox.Show("Login OK");
// Now convert the result variable to the exact datatype
// expected for checkedin, here I suppose you want an integer
checkedIN = Convert.ToInt32(result);
.....
}
else
MessageBox.Show("Login Failed");
}
Note how I have replaced your string concatenation with a proper use of parameters to avoid parsing problems and sql injection hacks. Finally every disposable object (connection in particular) should go inside a using block
I have a slight issue, I have a ASP.NET Webforms application. I'm sending over a url?id=X were X is my database index or id.
I have a C# class file to run my SQL connection and query. Here is the code:
public DataTable ViewProduct(string id)
{
try
{
string cmdStr = "SELECT * Products WHERE Idx_ProductId = " + id;
DBOps dbops = new DBOps();
DataTable vpTbl = dbops.RetrieveTable(cmdStr, ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString);
return vpTbl;
}
catch (Exception e)
{
return null;
}
}
So as you can see my problem lies within string cmdStr = "SQL Query" + variable;
I'm passing over my index or id through the URL then requesting it and turning it into a string then using ViewProduct(productId).
I don't know what syntax or how to add the id into my C# string sql query. I've tried:
string cmdStr = "SELECT * Products WHERE Idx_ProductId = #0" + id;
string cmdStr = "SELECT * Products WHERE Idx_ProductId = {0}" + id;
also what I have currently to no avail.
I was so sure this would be a duplicate of some canonical question about parameterized queries in C#, but apparently there isn't one (see this)!
You should parameterize your query - if you don't, you run the risk of a malicious piece of code injecting itself into your query. For example, if your current code could run against the database, it would be trivial to make that code do something like this:
// string id = "1 OR 1=1"
"SELECT * Products WHERE Idx_ProductId = 1 OR 1=1" // will return all product rows
// string id = "NULL; SELECT * FROM UserPasswords" - return contents of another table
// string id = "NULL; DROP TABLE Products" - uh oh
// etc....
ADO.NET provides very simple functionality to parameterize your queries, and your DBOps class most assuredly is not using it (you're passing in a built up command string). Instead you should do something like this:
public DataTable ViewProduct(string id)
{
try
{
string connStr = ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
// #id is very important here!
// this should really be refactored - SELECT * is a bad idea
// someone might add or remove a column you expect, or change the order of columns at some point
cmd.CommandText = "SELECT * Products WHERE Idx_ProductId = #id";
// this will properly escape/prevent malicious versions of id
// use the correct type - if it's int, SqlDbType.Int, etc.
cmd.Parameters.Add("#id", SqlDbType.Varchar).Value = id;
using (SqlDataReader reader = cmd.ExecuteReader())
{
DataTable vpTbl = new DataTable();
vpTbl.Load(reader);
return vpTbl;
}
}
}
}
catch (Exception e)
{
// do some meaningful logging, possibly "throw;" exception - don't just return null!
// callers won't know why null got returned - because there are no rows? because the connection couldn't be made to the database? because of something else?
}
}
Now, if someone tries to pass "NULL; SELECT * FROM SensitiveData", it will be properly parameterized. ADO.NET/Sql Server will convert this to:
DECLARE #id VARCHAR(100) = 'NULL; SELECT * FROM SensitiveData';
SELECT * FROM PRoducts WHERE Idx_ProductId = #id;
which will return no results (unless you have a Idx_ProductId that actually is that string) instead of returning the results of the second SELECT.
Some additional reading:
https://security.stackexchange.com/questions/25684/how-can-i-explain-sql-injection-without-technical-jargon
Difference between Parameters.Add and Parameters.AddWithValue
SQL injection on INSERT
Avoiding SQL injection without parameters
How do I create a parameterized SQL query? Why Should I? (VB.NET)
How can I prevent SQL injection in PHP? (PHP specific, but many helpful points)
Is there a canonical question telling people why they should use SQL parameters?
What type Products.Idx_ProductId is?
Probably it is string, than you need to use quotes: "... = '" + id.Trim() + "'";
I get this run time error and my id is not null I checked it in my code which you will see and I'm using telerik GridView
this is the run time error
The parameterized query '(#_fName nvarchar(4),#_lName nvarchar(2),#_phone nvarchar(6),#_a' expects the parameter '#_id', which was not supplied.
I'm trying to get the id from another form that's why I wrote it like this
here's my code in my first layer
private void btnEdt_Click(object sender, EventArgs e)
{
Ref_View_Model = new View_model._View_Model();
Ref_C = new Customers();
foreach (var RowInfo in Ref_C.radGridView1.SelectedRows)
{
FireCell = RowInfo.Cells[0].Value.ToString();
if (FireCell==null)
{
MessageBox.Show("null");
}
}
//Ref_C.radGridView1.CurrentRow.Delete();
Ref_C.customersTableAdapter.Update(Ref_C.sales_and_Inventory_SystemDataSet);
Ref_C.customersTableAdapter.Fill(Ref_C.sales_and_Inventory_SystemDataSet.Customers);
Ref_View_Model.GetEditCustomers(FireCell, txtFName.Text, txtLName.Text, txtPhn.Text, txtDdrss.Text);
}
here's my code in the last layer
public void EditCustomres( string _id,string _fName, string _lName,string _phone, string _address)
{
Connection_String = #"Data Source=MOSTAFA-PC;Initial Catalog=" + "Sales and Inventory System" + ";Integrated Security=TrueData Source=MOSTAFA-PC;Initial Catalog=" + "Sales and Inventory System" + ";Integrated Security=True;";
Query = "update Customers " +
"set FName=#_fName ,LName=#_lName ,Phone=#_phone ,[Address]=#_address" +" "+
"where Id like #_id";
using (Con=new SqlConnection(Connection_String))
using (Cmd=new SqlCommand(Query,Con))
{
Cmd.Parameters.Add("#_fName", SqlDbType.NVarChar);
Cmd.Parameters.Add("#_lName", SqlDbType.NVarChar);
Cmd.Parameters.Add("#_phone", SqlDbType.NVarChar);
Cmd.Parameters.Add("#_address", SqlDbType.NVarChar);
Cmd.Parameters.Add("#_id", SqlDbType.Int);
Con = Cmd.Connection;
Con.Open();
Cmd.Parameters["#_fName"].Value = _fName;
Cmd.Parameters["#_lName"].Value = _lName;
Cmd.Parameters["#_phone"].Value = _phone;
Cmd.Parameters["#_address"].Value = _address;
Cmd.Parameters["#_id"].Value = _id;
Cmd.ExecuteNonQuery();
Cmd.Dispose();
}
}
You really don't want to use LIKE in this case, unless you have very specific needs for it to update things that look like the ID you're passing in, but are not quite it...
You're passing in #_id as an SqlDbType.Int, but the variable is actually of type string, this will cause a conversion to happen under the hood. In case you're passing in an empty string, the value is converted to null, which will result in the error you mentioned in your post. Check the code that leads into calling EditCustomres to ensure that it actually passes in the correct value. Adding argument checks, like the one I added, will help you track these kinds of issues much earlier in the callstack.
Step one is to get rid of your LIKE statement, so please update the query to use:
where id = #_id
Then update your code, since you expect the _id variable to be in int, you can't just assign a string to it, which is probably why it's getting reset to null. Either update the method to accept an int parameter instead of string id, or parse the int in your method before adding the parameter:
int idValue = -1;
if (!int.TryParse(_id, NumberStyles.Integer, CultureInfo.InvariantCulture, out idValue))
{
throw new ArgumentException("id", "Id must be a string which contains an integer value, the value of 'id' was: '" + _id + "'");
}
Cmd.Parameters.Add("#_id", SqlDbType.Int).Value = idValue;
You may need to add a using statement to your file:
using System.Globalization;
This is where NumberStyles and CultureInfo are defined. Normally Visual Studio will suggest where you can find these items crtl+. will pop-up a screen which will add this statement automatically.
End result would be:
using System.Globalization;
....
....
public void EditCustomers( string _id,string _fName, string _lName,string _phone, string _address)
{
int idValue = -1;
if (!int.TryParse(_id, NumberStyles.Integer, CultureInfo.InvariantCulture, out idValue))
{
string message = "Id must be a string which contains an integer value, the value of 'id' was: '" + _id + "'";
throw new ArgumentException("_id", message);
}
Connection_String = #"Data Source=MOSTAFA-PC;Initial Catalog=" + "Sales and Inventory System" + ";Integrated Security=TrueData Source=MOSTAFA-PC;Initial Catalog=" + "Sales and Inventory System" + ";Integrated Security=True;";
Query = #"update Customers
set FName=#_fName, LName=#_lName, Phone=#_phone,[Address]=#_address
where Id = #_id";
using (Con=new SqlConnection(Connection_String))
using (Cmd=new SqlCommand(Query, con))
{
Cmd.Parameters.AddWithValue("#_fName", _fName);
Cmd.Parameters.AddWithValue("#_lName", _lName);
Cmd.Parameters.AddWithValue("#_phone", _phone);
Cmd.Parameters.AddWithValue("#_address", _address);
Cmd.Parameters.AddWithValue("#_id", idValue);
Con.Open();
Cmd.ExecuteNonQuery();
}
}
I simplified the code a bit as well. using a verbatim string for your SQL statement, removing the call to Dispose (which is already covered by your use of using(cmd) and removing the Con=Cmd.Connection, since it really cannot have any other value.
Using the .AddWithValue method is also easier than creating and setting the value individually.
Be really careful with solutions that require you to concatenate your string to form the SQL query on the SQL Server side, this could result in the value injecting unwanted SQL statements that can expose your data to the outside world or allow outsiders to destroy your data.
Also be careful with LIKE statements for matching update values. Unless you have very strong argument validation on the code paths calling into this statement, passing in id="?" or id="%%" or simply id=string.Empty to your function would likely update all records and will thus overwrite all of them to have the same values. %1% will match 1, 10, 21, 31, 11, 100003... Which is highly unlikely the desired behavior.
Using = over like in delete and update statements is almost always the desired solution. If you get errors with = you're likely mixing data types (string where int is expected for example).
Your LIKE clause for id is incorrect. It should be like this:
Id LIKE '%' + #_id + '%'
Or:
Cmd.Parameters.AddWithValue("#_id","%" + _id+ "%");
Or:
Cmd.Parameters.Add("#_id", SqlDbType.Int).Value = "%" + _id + "%";
Although it would be better that you use simple = instead of Like:
where Id = #_id