I'm running a database in SQL2012 and using Visual Studio2012 C# to build a software that interacts with the database, and I've been trying to add a button that interacts with a textbox or something similar that lets the user add/edit rows in the database.
Code:
try
{
string conString = "Data Source=MIRANDA-PC;Initial Catalog=Futebol do Rosa;Integrated Security=True";
SqlConnection con = new SqlConnection(conString);
string selectSql = "Update Players$ SET Player Name='" + textBox3.Text + "' WHERE Player ID= 1";
SqlCommand cmd = new SqlCommand(selectSql, con);
con.Open();
cmd.ExecuteNonQuery();
MessageBox.Show("The values have been UPDATED");
}
catch{
MessageBox.Show("not so fast ***, error found in your ******** code");
}
Ignoring the safety issues (inline SQL is bad. Very bad.) Your update has some fundamental errors. Try:
string selectSql = "Update Players SET Players.Name='" + textBox3.Text +
"' WHERE Players.ID= 1";
Your table columns need to be associated to the table with a . and the table name has to be the same as the one you are updating. I am going on the assumption here that your table name is Players
The code in your link isn't even safe.
Your SqlConnction and SqlCommand will not dispose
The end user can use SQL Injection
Throw your SqlConnection and SqlCommand in an using statement.
using (SqlConnection con = new SqlConnection(constring))
{
using (SqlCommand cmd = new SqlCommand("your query here", con))
{
con.Open();
cmd.ExecuteNonQuery();
}
}
Add parameters to your SqlCommand to avoid SqlInjection
cmd.Parameters.AddWithValue("#param", value);
Create your own class for database interaction and don't put everything in one class or form.
If you let us know what the error is, we can help you more.
Also a good thing is to google your error first.
Related
I have a small table (tbl_user_favs) that is meant to store user favorites. Column 1 is the user ID, and then every column after that is a slot for a selected favorite PC to be stored, denoted Slot1, Slot2.
using (SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\UserFavorites.mdf;Initial Catalog=tbl_user_favs;Integrated Security=True;Connect Timeout=30"))
{
string cmdString = ("SELECT * FROM tbl_user_favs WHERE UserID = '" + Globals.emailUID + "'");
SqlCommand cmd = new SqlCommand(cmdString, con);
cmd.Parameters.Add("#Slot1", SqlDbType.VarChar).Value = PCnum;
DataSet loginCredentials = new DataSet();
SqlDataAdapter dataAdapter;
con.Open();
//dataAdapter = new SqlDataAdapter(cmdString, con);
dataAdapter = new SqlDataAdapter(cmd);
dataAdapter.Fill(loginCredentials);
//cmd.ExecuteNonQuery();
con.Close();
}
Code executes, but it does not add the PCnum to the database next to the UserID. It should lok through the rows, find the UserID that matches the logged in user, Globals.emailUId, and add the PCnum to an open slot. Without worrying yet how to dynamically increment the Slots, why isn't this insert adding the PCnum to Slot 1? I've seen some tutorials use ExecuteNonQuery, and some use the dataAdapter, but both have the same result. I suspect there is something off with my SQL? Thank you
There are a couple things going on here.
First is that you are using "Parameters" incorrectly. It's supposed to add data to your query, not data to the database/row/column after a query has been made.
sql parameterized query in C# with string
Second, you are doing a select query, so you are only getting data from the db, not putting data into it.
To do what you want, you'd need to do this instead: (I don't have a good way to test this, so it may need tweaks, but it should be close.)
using (SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\UserFavorites.mdf;Initial Catalog=tbl_user_favs;Integrated Security=True;Connect Timeout=30"))
{
string cmdString = ("UPDATE tbl_user_favs SET Slot1 = #Slot1 WHERE UserID = #EmailUID");
SqlCommand cmd = new SqlCommand(cmdString, con);
cmd.Parameters.AddWithValue("#Slot1", PCnum);
cmd.Parameters.AddWithValue("#EmailUID", Globals.emailUID);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
You no longer need the DataSet or the SqlDataAdapter.
Since you seem to be confused on what parameterization is and why to use it, check out this question, too.
And here's just some more reading on the topic in general. I used these articles as resources for this answer:
https://visualstudiomagazine.com/articles/2017/07/01/parameterized-queries.aspx
https://www.c-sharpcorner.com/UploadFile/a20beb/why-should-always-use-the-parameterized-query-to-avoid-sql-i/
I am working on a project where the user gets to generate a set of licenses keys and export it into a text file. The information is then displayed in a listbox as shown below. I am using C# and Windows Forms:
On top of this I would also like to save the details from the listbox into the local SQL Server database for record keeping purposes in my application. I have tried out various methods I found online to do this but all were unsuccessful.
One of the methods I've found is from this link:
https://www.youtube.com/watch?v=hUZGyA6UKGI&t=0s&index=26&list=PLZEMJ7iJtVdq9aMAiDfRlMoNrzGaWOfkZ
Here is the code I used from the video tutorial:
private void recordinserted(List<string>li)
{
StringBuilder stringbi = new StringBuilder(string.Empty);
foreach (string item in li)
{
const string qry = "Insert into [LicenseDB](Comapny Name, Software Name, LicenseKeys)values";
stringbi.AppendFormat("{0}('{i}');",qry,item);
}
SqlConnection con = new SqlConnection();
con.ConnectionString = (#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\User\Documents\Database.mdf;Integrated Security=True;Connect Timeout=30");
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = stringbi.ToString();
cmd.Connection = con;
int a = cmd.ExecuteNonQuery();
if (a > 0)
{
MessageBox.Show("inserted");
}
}
// adding into local database (method placed in button click)
List<string> li = new List<string>();
foreach (ListViewItem item in lbGeneratedKeys.Items)
{
if (item.Selected)
{
li.Add(item.Text);
}
recordinserted(li);
}
I realized that the person was using C# with ASP.Net and makes use of ListITem property which Windows Form does not have.
The other method I used is the classic SqlConnection method:
//adding into local database
using (SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\User\Documents\Database.mdf;Integrated Security=True;Connect Timeout=30"))
{
con.Open();
SqlCommand cmd = new SqlCommand("INSERT INTO LicenseDB (Company Name, Software Name, LicenseKeys,LicenseFileNo) VALUES (#cName, #sName, #lKeys, #lno)");
cmd.CommandType = CommandType.Text;
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
lbGeneratedKeys.Items.Add(dr[0].ToString());
lbGeneratedKeys.Items.Add(dr[1].ToString());
lbGeneratedKeys.Items.Add(dr[2].ToString());
lbGeneratedKeys.Items.Add(dr[3].ToString());
}
}
I used (dr[0].ToString()) to read each line from the listbox to be added into the database, where each number represents a row in the listbox. Eg. [0] represents the company name in the listbox. However when I try to execute the program there's an error saying that the SqlDataReader row is not initialized.
Also, since my program has the algorithm for users to generate more than one license keys, I also need help on how I can group these several rows of generated license keys to be added into one database column in the Database table. For instance in my UI above, I chose to generate 3 license keys and each license key takes up a row in the ListBox, I would like to group these three rows together to be placed under one database column variable (licenseKeys). I would like the algorithm to be able to read the generated keys dynamically as well as the user can generate as many license keys as needed.
I hope I had understood your problem:
First of all, I think is very important to define your data model. For example, in order to allow that a user can define a lot of keys, I would use another table where all the keys were stored, after that you need to define if a same key could be related to more than one row on the table 'LicenseDB' (in the table 'LicenseDB' you would have the columns Company Name, Software Name, LicenseFileNo). If so you'd have the relation (n:n) and then you would need to build another intermediate table that defines the relation between the table 'keys' and the table 'LicenseDB' . If it's not the case, then you simple define the relation between 'keys' and 'LicenseDB' (n:1) adding a column licenseDbID to the table 'keys' that relation many keys to one row in the table 'LicenseDB'
On the other hand, the problem with your code is that you are trying to insert data and not to read data, so you don't need a DataReader instead of that you just simply could implement something like this:
using (SqlConnection con = new SqlConnection('YOUR STRING CONNECTION'))
{
con.Open();
string comando = "INSERT INTO LicenseDB (companie, software) VALUES ('" + lbGeneratedKeys.Items[0].ToString() + "','" + lbGeneratedKeys.Items[1].ToString() + "')";
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = comando;
cmd.Connection = con;
cmd.ExecuteNonQuery();
}
In this case, two values are inserted into the table LicenseDB the values for companie name and software name.
I hope I had helped you.
I referred back to my previous school project and managed to save my listbox data into the SQL database. I have two listboxes in total: 1 for allowing user to export as text file, and the second to specifically store generated license keys only. The second listbox is set to not visible in my program.
The codes I used:
private void exportKey_Click(object sender, EventArgs e)
{
//adding into local database
//excludes adding licensekeys
SqlConnection sqlCon = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\User\Documents\Database.mdf;Integrated Security=True;Connect Timeout=30");
sqlCon.Open();
SqlCommand sqlCmd = new SqlCommand("addLicensedata", sqlCon);
sqlCmd.CommandType = CommandType.StoredProcedure;
sqlCmd.Parameters.AddWithValue(#"companyName", companyTextbox.Text.Trim());
sqlCmd.Parameters.AddWithValue(#"softwareName", softwareTextbox.Text.Trim());
sqlCmd.Parameters.AddWithValue(#"prodID", prodidTextbox.Text.Trim());
sqlCmd.Parameters.AddWithValue(#"licenseType", cbLicensetype.Text.Trim());
sqlCmd.Parameters.AddWithValue(#"LicenseNo", licensekeyNum.Text.Trim()); //no of license keys
sqlCmd.ExecuteNonQuery();
//MessageBox.Show("Added to database");
sqlCon.Close();
if (cbLicensetype.SelectedItem.ToString() == "Trial")
{
sqlCmd.Parameters.AddWithValue(#"TrialDays", tbTrialdays.Text.Trim());
}
addtoFKtable();
private void addtoFKtable()
{
SqlConnection Con = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\User\Documents\Database.mdf;Integrated Security=True;Connect Timeout=30");
Con.Open();
SqlCommand Cmd = new SqlCommand("addLicensekeys", Con);
Cmd.CommandType = CommandType.StoredProcedure;
Cmd.Parameters.AddWithValue(#"LicenseNo", licensekeyNum.Text.Trim());
Cmd.Parameters.AddWithValue(#"LicenseKeys", lbHidden.Text.Trim());
Cmd.Parameters.AddWithValue(#"prodID", prodidTextbox.Text.Trim());
Cmd.Parameters.AddWithValue(#"companyName", companyTextbox.Text.Trim());
Cmd.ExecuteNonQuery();
//MessageBox.Show("Added license to database");
Con.Close();
}
I stored my SQL commands as a stored procedure within the database, and just called the command in my codes.
try
{
OleDbConnection myConnection = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Users\\HP8200\\Desktop\\ELISA2014Data.mdb ;Persist Security Info=False;");
myConnection.Open();
// Create Oledb command to execute particular query
OleDbCommand myCommand = new OleDbCommand();
myCommand.Connection = myConnection;
// Query to create table with specified data columne
myCommand.CommandText = "CREATE TABLE UXZona([IDZona] int, [Morada] text)";
//myCommand.ExecuteNonQuery();
MessageBox.Show("Tabela criada");
}
catch
{
OleDbConnection myConnection = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Users\\HP8200\\Desktop\\ELISA2014Data.mdb ;Persist Security Info=False;");
myConnection.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO UXZona (IDZona, Morada) VALUES ('" +
transaction.UnloadPlaceAddress.AddressID + "','" +
transaction.UnloadPlaceAddress.AddressLine2 + "')";
cmd.ExecuteNonQuery();
MessageBox.Show("Dados inseridos");
}
I need to insert data into the database but it isn't working. I launch the program and there are no errors, I do everything but when I check the database the table is empty.
UPDATE
Now when i launch the program I have this error:
"System.InvalidOperationException: 'ExecuteNonQuery: Connection property has not been initialized." on cmd.ExecuteNonQuery();
There are a number of things wrong! I give below corrected code:
try
{
bool success = false;
using (var myConnection = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Users\\HP8200\\Desktop\\ELISA2014Data.mdb ;Persist Security Info=False;"))
{
// Create Oledb command to execute particular query
using (var myCommand = new OleDbCommand())
{
myCommand.Connection = myConnection;
// Query to create table with specified data columne
//myCommand.CommandText = "CREATE TABLE UXZona([IDZona] int, [Morada] text)";
//myCommand.ExecuteNonQuery();
//MessageBox.Show("Tabela criada");
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO UXZona (IDZona, Morada) VALUES (#id, #morada)";
var param = cmd.CreateParameter();
param.ParameterName = "#id";
param.OleDbType = OleDbType.Integer;
param.Value = transaction.UnloadPlaceAddress.AddressID;
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "#morada";
param.OleDbType = OleDbType.VarChar;
param.Value = transaction.UnloadPlaceAddress.AddressLine2;
cmd.Parameters.Add(param);
myConnection.Open();
if (cmd.ExecuteNonQuery() == 1)
{
success = true;
}
}
}
if (success)
{
MessageBox.Show("Dados inseridos");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
By way of explanation. I have commented out (but not deleted) all references to creating the table. Table creation and table insertion should be in two different routines. Normally you only create a table once, but insert is probably called many times.
I have placed the OleDbConnection and OleDbCommand within using loops. This is good practice, as they both implement IDisposable. Writing your code like this means that the Garbage Collector (GC) knows immediately that it can safely dispose of the objects after use.
I have changed the insert statement such that it takes parameters. This is highly recommended practice to safeguard against SQL Injection (if you do not know what this is please Google it). In fact Access is relatively immune from the worst forms of SQL Injection, because it rejects any command that contains multiple statements, but please get into good habits. With time you will progress to other databases which do not have this restriction.
I deliberately wait before opening the connection until just before it is needed. Connections consume resources, so it is good practice to use them as sparingly as possible. Also for this reason, I have moved your success message outside of the using loops. This means that the cleanup of resources is not waiting for the user to click OK in the message box.
Finally try catch is all well and good, but normally you want to know why the error occurred. Hence you add (Exception ex) to catch so that you can find the reason.
PS What I forgot to mention. In your original INSERT, you were surrounding both VALUES with single quotes. Only use single quotes for strings/text. Integers and other numbers require no quotes. If you quote them, the database will treat it as a string and you will get a data type error.
I was wondering if it is possible for the update button to save the changes made in the table. I wrote this code but I have no idea how it could possibly work
This is the code i wrote for the update button:
string conString = "Data Source=MIRANDA-PC;Initial Catalog=Futebol do Rosa;Integrated Security=True";
SqlConnection con = new SqlConnection(conString);
string selectSql = "Update Players$ set Player Name='" + dataGridView2.Text + "";
SqlCommand cmd = new SqlCommand(selectSql, con);
con.Open();
This is the table I want to update the values in:
Well, you just need to execute your query with ExecuteNonQuery.
But more important, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
Also use using statement to dispose your SqlConnection and SqlCommand.
And if your table or column names more than one word, you need to use them with [] as [Player Name]. And honestly, it is a little bit weird to use $ sign in a table name.
using(SqlConnection con = new SqlConnection(conString))
using(SqlCommand cmd = con.CreateCommand())
{
cmd.CommandText = "Update Players$ set [Player Name] = #name";
cmd.Parameters.Add("#name", SqlDbType.NVarChar, 16).Value = dataGridView2.Text;
con.Open();
cmd.ExecuteNonQuery();
}
You have to execute your SQL query with your db object.
dbinstance.ExecuteSqlCommand(string sqlcommand, object[] params);
This method is both for DDL and DML.
you can also use ExecuteNonQuery method.
cmd.CommandText = "Update Players$ set [Player Name] = #Playername";
cmd.Parameters.Add("#Playername", SqlDbType.NVarChar, 16).Value = dataGridView2.Text;
con.Open();
cmd.ExecuteNonQuery();
The best solution (if possible) to to convert your DAL (Data Access Layer) to Entity-framework based, instead of writing your own SQL queries. This is safe-by-design and never is vulnerable to SQL Injection of any kind.
Here is some mockup code:
using (AppEntities currDb = new AppEntities)
{
Players PlayerToEdit =
from player in currDb.Players
where player.PlayerID == lngPlayerID
select player.First();
PlayerToEdit.PlayerName = dataGridView2.Text;
currDb.SaveChanges();
}
You can read about it some more here:
https://msdn.microsoft.com/en-us/data/ef.aspx
This question already has answers here:
The multi-part identifier "TextBox1.Text" could not be bound in C# ASP.NET?
(3 answers)
Closed 9 years ago.
if (validateEmailId(email))
{
pictureBox5.Visible = true;
SqlConnection con = new SqlConnection("conection string");
SqlCommand cmd2 = new SqlCommand("UPDATE sumant SET email=" + email + " WHERE code ='" + textBox2.Text + "' ", con);
cmd2.Connection = con;
cmd2.Connection.Open();
cmd2.ExecuteNonQuery();//line 7
con.Close();
}
validateEmailId is a function which validates the email entered(using regular expression)..
The email entered in the 'email' textbox is validated and is returned to the above function..
When the control passes to line 7 following error is encountered:
The multi-part identifier "sxxx#yahoo.com" could not be bound.
It means sxxx#yahoo.com has passed the validation test, but a problem occurred in line 7.
On the SQL end, the column 'email' has varchar(50) as its data type...I don't think that's an issue....
You should at least put single quotes around the email adress:
SqlCommand cmd2 = new SqlCommand("UPDATE sumant SET email='" + email + "' WHERE code ='" + textBox2.Text + "' ", con);
However, this is not a good way of passing in params, as you are leaving this wide open for SQL injection attacks...
A better way would be to use a parameterized query, like this:
SqlCommand cmd2 = new SqlCommand("UPDATE sumant SET email=#email WHERE code=#code", con);
cmd2.Parameters.AddWithValue("#email", email);
cmd2.Parameters.AddWithValue("#code", textBox2.Text);
Then you don't need to supply the single quotes, and you're at the same time safeguarding against SQL injection attacks...
Ouch, I smell SQL injection and lack of disposal. Try this:
using (SqlConnection con = new SqlConnection("conection string")) {
using (SqlCommand cmd2 = new SqlCommand("UPDATE sumant SET email=#Email WHERE code = #Code", con)) {
cmd2.Parameters.AddWithValue("#Email", email);
cmd2.Parameters.AddWithValue("#Code", textBox2.Text);
con.Open();
cmd2.ExecuteNonQuery();
}
}
The using directives will close the SqlConnection and SqlCommand no matter if they fail or execute properly. The SqlParameters will prevent any form of SQL injection.
Another sidenote: your passing the conn argument to the SqlCommand constructor AND are setting the connection property of the SqlCommand after that, passing the SqlConnection to the SqlCommand already sets the connection property.