I am making a C# tool that connects to a SQL database to manage users for another program I created. I'm displaying the Users in a ListBox, and I can add/delete users. Things got weird after I deleted some profiles, and I thought that could have something to do with how I delete the row from the database. I'm using an Id that automatically increases with every new user creation. This is my code for deleting from the database:
using (conn = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand("DELETE FROM myDatabase WHERE Id = '" + (listBox1.SelectedIndex + 1) + "'", conn))
{
conn.Open();
command.ExecuteNonQuery();
}
and this is how I load the users into my listbox:
using (conn = new SqlConnection(connectionString))
using (SqlDataAdapter sqlAdapt = new SqlDataAdapter("SELECT * FROM myDatabase", conn))
{
DataTable dataTable = new DataTable();
sqlAdapt.Fill(dataTable);
listBox1.DisplayMember = "Name";
listBox1.ValueMember = "Id";
listBox1.DataSource = dataTable;
}
How can I delete the correct row from the database?
You should use the property SelectedValue to find your ID not the SelectedIndex
if(listBox1.SelectedValue != null)
{
int userID = Convert.ToInt32(listBox1.SelectedValue);
using (conn = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand("DELETE FROM myDatabase WHERE Id = #uid", conn))
{
conn.Open();
command.Parameters.Add("#uid", MySqlDbType.Int32).Value = userID;
command.ExecuteNonQuery();
}
}
The problem with SelectedIndex is that this value goes from 0 to the max number of items in the listbox. This value has nothing to do with the ID of your user automatically calculated by your database. (After just one delete and one add these value are out of synch)
Note also that an sql text should never built using string concatenation. This is a well know security problem called Sql Injection.
"DELETE FROM myDatabase WHERE Id = '" + (listBox1.SelectedIndex + 1) + "'"
I'm not sure about mySQL, but it looks like you pass a string instead of an int.
When you pass a parameter as a number you should remove the " ' ".
so, it will look like:
"DELETE FROM myDatabase WHERE Id = " + (listBox1.SelectedValue)
Related
This is my code, and I want to be able to search for a name, and then pull from the database the name, status, member_id into the textboxes in my form.
I got the name to work but how do I get the other columns and parse the output into the textboxes with the additional columns (member_id, status)? Let's say the other textboxes have the standard name such as textbox2, 3, 4...
string connetionString = null;
SqlConnection connection;
SqlCommand command;
string sql = null;
string sql1 = null;
SqlDataReader dataReader;
connetionString = "Data Source=......"
sql = "SELECT NAME FROM Test_Employee WHERE Name LIKE '" + textBox1.Text.ToString() + "%'";
connection = new SqlConnection(connetionString);
{
connection.Open();
command = new SqlCommand(sql, connection);
dataReader = command.ExecuteReader();
while (dataReader.Read())
{
textBox9.Text = dataReader[0].ToString();
textBox7.Text = dataReader[0].ToString();
}
connection.Close();
}
Are the fields Member_Id and Status also in the table Test_Employee? You can add them in your Select statement and get them from your SqlReader, like the code below (assuming you are using c#7 and below). You may copy and paste this code.
var connectionString = "";
var sql = #"SELECT TOP 1 Name, Member_Id, Status
FROM Test_Employee
WHERE Name LIKE #name + '%'";
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.Add("name", SqlDbType.NVarChar, 100).Value = textBox1.Text.ToString();
connection.Open();
var reader = command.ExecuteReader();
if (reader.Read())
{
textBox9.Text = dataReader["Name"].ToString();
textBox7.Text = dataReader["Name"].ToString();
textBox2.Text = dataReader["Member_Id"].ToString();
textBox3.Text = dataReader["Status"].ToString();
}
}
You will notice that instead of including the Textbox1.Text's value in your Select statement, it is added as a parameter in the SQLCommand object's Parameters. In this way your query is protected from SQL Injection. If you want to learn more, you can search c# sqlcommand parameters and why it is very important to build data access code this way.
Also, notice that I added Top 1 in your Select statement, and instead of using while, I am using if. This is because a textbox can only hold 1 result at a time in a comprehensible way. If you meant to show multiple results clearly, you need to use a different control other than a TextBox.
The using statements allow you to dispose the connection, so you don't have to call connection.Close().
I am not getting, how to do insert and update of the data in C# WinForms on single button click.
private void save_Click(object sender, EventArgs e)
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = "data source=Sai;database=kaur; user id=sa;password=azxc;";
cn.Open();
string gen;
if (radioButton1.Checked == true)
gen = "Male";
else
gen = "Female";
string clas = null;
clas = comboBox1.Text;
string section = null;
section = comboBox2.Text;
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "insert into studetail values('" + textBox1.Text + "','" + textBox2.Text + "','" + gen + "','" + textBox3.Text + "','" + clas + "','" + section + "')";
cmd.Connection = cn;
int n = cmd.ExecuteNonQuery();
if (n > 0)
MessageBox.Show(n + " Row Inserted.");
else
MessageBox.Show("Insertion failed.");
SqlDataAdapter da = new SqlDataAdapter("select * from studetail ", cn);
DataTable dt = new DataTable();
da.Fill(dt);
dataGridView1.DataSource = dt;
You can add a deletion before the insertion:
private void save_Click(object sender, EventArgs e)
{
DeletePerson(id); // add this
SqlConnection cn = new SqlConnection();
...
}
public void DeletePerson(int id)
{
using(SqlConnection connection = new SqlConnection(credentials))
{
connection.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = connection;
cmd.CommandText = "delete from studetail where someUniqeIdColumn = " + id;
cmd.ExecuteNonQuery();
}
}
Using responsible to dispose the connection.
Consider using Entity Framework or LINQ to SQL.
You are exposed to SQL injection.
First off the SQL query isn't quite right. It should look something like the following:
INSERT INTO studetail (columnName1, columnName2, ...columnNameN)
VALUES (value1, value2, ...valueN);
Where the column names are the columns where you want data to be inserted, and the values are the data you want inserted into said columns.
You should also be disposing the connection by wrapping the connection within a using statement.
using(var con = new SqlConnection(connectionString))
{
con.Open();
//rest of code that needs a connection here
}
Additionally, you need to be wary of SQL injection. I highly suggest reading this example from the MSDN website. It will give you an example of using an SQL Update and avoiding SQL injection with use of SqlCommand.Paramaters property.
You should also have a Primary Key in your database tables, if you don't already, so you can uniquely identify each record in a table.
To do an update and a save on the same button, you will need to check if a row already exists for the data that is being edited. This when a Primary comes in handy. You will want to check your database to see if a record already exists
SELECT 1 FROM studetail WHERE <Condition>
The WHERE condition will be the way you uniquely identify (a Primary Key) a row in your table. If the rows in the table are uniquely identified, the above SQL statement will return 1 if a value exists, which means you can UPDATE or 0 if no record exists, so you can INSERT
I'm making mysql register/login system in c#. I'm able to register and login with it.
I'm verify account with:
MySqlConnection conn = new MySqlConnection(db_creds);
try { conn.Open(); }
catch { throw new Exception("Can't access database"); }
MySqlDataAdapter adapter;
DataTable table = new DataTable();
string query = "SELECT `Nickname`, `Password` FROM `" + db_table + "` WHERE `Nickname` = '" + nickname + "' AND `Password` = '" + password + "'";
adapter = new MySqlDataAdapter(query, conn);
adapter.Fill(table);
conn.Close();
if(table.Rows.Count <= 0)
{
return false;
}
else { return true; }
After Nickname and Password I have varchar named active. My question is:
How can I change "active" (only for this user) to 1 when user succesfully logged in? and when logoff change it to 0?
To alter a single row in the table, you need to get it's ID(unique identifier for this table). Let the name for this unique column be str_Id, then retrieve this id for the particular user name and password. Then you can update the active state based on this unique identifier.
Another important advise for you is, don't use this type of plain-text queries, which will opens a wide door for SQL Injection. So i strongly recommend you to use parameterized queries as follows;
string query = "SELECT Nickname,str_Id FROM your_table_name" +
" WHERE Nickname =#nickname AND Password = #password";
MySqlConnection con = new MySqlConnection();
// Creating parameterized command
MySqlCommand cmd = new MySqlCommand(query, con);
cmd.Parameters.Add("#nickname", MySqlDbType.VarChar).Value = nickname;
cmd.Parameters.Add("#password", MySqlDbType.VarChar).Value = password;
MySqlDataAdapter adapter = new MySqlDataAdapter(cmd);
DataTable table = new DataTable();
// Collect the details to a DataTable
adapter.Fill(table);
if (table.Rows.Count>0) // Means there is some record found
{
// Get theUnique ID for the matching record
string uniqueId = table.Rows[0]["str_Id"].ToString();
// Update active state for that particular user
query = "Update your_table_name set active='0' Where str_Id=#str_Id";
cmd = new MySqlCommand(query, con);
cmd.Parameters.Add("#str_Id", MySqlDbType.VarChar).Value = uniqueId;
// Execute command here
}
else
{
// Print message thet no user found
}
When you verify if user exists and if password is correct and return message there you need to add update command for your database.
With that update command you need to update column ACTIVE to 1 but to that user, so you need to use this:
UPDATE table_name
SET column1=value1
WHERE some_column=some_value;
So in your case
UPDATE db_table SET active = 1 WHERE nickname = ' + nickname + '
So user now have status of ACTIVE.
Now you need to set it to inactive when he log off, so you do that when he press log off button or when he close the program, but with same principle
UPDATE db_table SET active = 0 WHERE nickname = ' + nickname + '
This is our code to prevent the same data from being added into SQL from our C# program but only the first same data will not be added in. The remaining ones adds the same data into SQL despite our prevention in our C# program. Can somebody help us troubleshoot?
in order not to duplicate data in database usually you set some constraints to your database. By having a unique field in database you can prevent multiple addition to your db.
Currently you are also fetching data from db to check if it exist already and that creates extra cost, just manipulate the design of db so that it won't accept the same column input twice
Count the value of data that is inserted
string constr = ConfigurationManager.ConnectionStrings["connstr"].ToString();
SqlConnection con = new SqlConnection(constr);
string sql1 = "SELECT COUNT (client_id) FROM client WHERE client_id = '" + txtid.Text + "' ";
SqlCommand cmd = new SqlCommand(sql1, con);
con.Open();
int temp = Convert.ToInt32(cmd.ExecuteScalar().ToString());
if (temp >0)
{
//show error message
}
You could check for the record you want to add, and if it doesn't exists, then add it to the table:
SqlConnection _cnt = new SqlConnection();
_cnt.ConnectionString = "Your Connection String";
SqlCommand _cmd = new SqlCommand();
_cmd.Connection = _cnt;
_cmd.CommandType = System.Data.CommandType.Text;
_cmd.CommandText = "SELECT id FROM myTable where Category=#Name";
_cmd.Parameters.Add("#Name", string);
_cmd.Parameters["#Name"].Value = newCatTitle;
_cnt.Open();
var idTemp = _cmd.ExecuteScalar();
_cmd.Dispose();
_cnt.Close();
_cnt.Dispose();
if (idTemp == null)
{
//Insert into table
}
else
{
//Message it already exists
}
UPDATE:
Thanks everyone, the code was not the issue, although the information regarding SQL injection was useful, my issue was that I was using an older version of my database which did not have the corresponding product ID so it was instead using the first product that it could find. Feel very stupid now but thanks for the suggestions.
I currently have the following code :
SqlConnection connection = new SqlConnection(#"Data Source=(LocalDB)\v11.0 AttachDbFilename=C:\Users\h8005267\Desktop\Practical Project\Build\System4\System\StockControl.mdf;Integrated Security=True;Connect Timeout=30");
connection.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Product WHERE ProductID='" + textBox3.Text + "'", connection);
SqlDataReader re = cmd.ExecuteReader();
if (re.Read())
{
textBox4.Text = re["ProductTitle"].ToString(); // only fills using first product in table
textBox5.Text = re["ProductPublisherArtist"].ToString();
comboBox1.Text = re["ProductType"].ToString();
textBox6.Text = re["Price"].ToString();
}
else
{
MessageBox.Show("Please enter a valid item barcode");
}
re.Close();
connection.Close();
The issue I am currently having is although the text boxes display the information on button click, the information displayed is only the first row of data in the database, NOT the row corresponding to the textbox3 in the sql statement
Try this instead. Avoid building SQL statement dynamically the way you are doing it. You are opening your database to risks of SQL Injection. Used parameters insead.
using (var connection = new SqlConnection("connection string"))
{
connection.Open();
using (var cmd = new SqlCommand("SELECT * FROM Product WHERE ProductID=#MYVALUE", connection))
{
cmd.Parameters.Add("#MYVALUE", SqlDbType.VarChar).Value = textBox3.Text;
SqlDataReader re = cmd.ExecuteReader();
if (re.Read())
{
textBox4.Text = re["ProductTitle"].ToString(); // only fills using first product in table
textBox5.Text = re["ProductPublisherArtist"].ToString();
comboBox1.Text = re["ProductType"].ToString();
textBox6.Text = re["Price"].ToString();
}
else
{
MessageBox.Show("Please enter a valid item barcode");
}
}
}
put a breakpoint on that line
SqlDataReader re = cmd.ExecuteReader();
and enter the following into textBox3
'; DROP TABLE Product; SELECT '
the ' are to be entered in your textbox. now execute your method and carefully read the resulting sql command... welcome to sql injection ;)
#M Patel: thx for your comment and you are perfectly right
The result would be the following SQL
SELECT * FROM Product WHERE ProductID=''; DROP TABLE Product; SELECT ''
And this would allow a malicious user to destroy your database.
To prevent that you should work with prepared Statements like M Patel suggested in his answer
you have SQL Injection problem with '" + textBox3.Text + "'"
and you don't have to name your controls like that, you have to use a meaningful names
you can use this code
using (SqlConnection connection = new SqlConnection(#"Data Source=(LocalDB)\v11.0 AttachDbFilename=C:\Users\h8005267\Desktop\Practical Project\Build\System4\System\StockControl.mdf;Integrated Security=True;Connect Timeout=30"))
{
connection.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Product WHERE ProductID=#ProductID", connection);
cmd.Parameters.AddWithValue("#ProductID", textBox3.Text);
SqlDataReader re = cmd.ExecuteReader();
if (re.Read())
{
textBox4.Text = re.GetString(re.GetOrdinal("ProductTitle")); // only fills using first product in table
textBox5.Text = re.GetString(re.GetOrdinal("ProductPublisherArtist"));
comboBox1.Text = re.GetString(re.GetOrdinal("ProductType"));
textBox6.Text = re.GetString(re.GetOrdinal("Price"));
}
else
{
MessageBox.Show("Please enter a valid item barcode");
}
re.Close();
}