Why isnt this working? it says invalid column name when i try to remove something after i added it
private void btnRemoveCommand_Click(object sender, EventArgs e)
{
connection = new SqlConnection(connectionString);
connection.Open();
for (int i = 0; i < listBox1.SelectedItems.Count; i++)
{
var sql = "DELETE FROM Commands WHERE commandName = " + listBox1.SelectedItems[i] + "";
listBox1.Items.Remove(listBox1.SelectedItems[i]);
SqlCommand cmd = new SqlCommand(sql, connection);
cmd.ExecuteNonQuery();
}
connection.Close();
}
this is the event that handles the addCommand to the database
private void btnAddCommand_Click(object sender, EventArgs e)
{
var sql = "INSERT INTO Commands(commandName, pathToCommand) VALUES(#commandName, #pathToCommand)";
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand cmd = new SqlCommand(sql, connection);
cmd.Parameters.AddWithValue("#commandName", tbxCommand.Text);
cmd.Parameters.AddWithValue("#pathToCommand", tbxPathToCommand.Text);
int affectedRows = cmd.ExecuteNonQuery();
}
}
Change
var sql = "DELETE FROM Commands WHERE commandName = " + listBox1.SelectedItems[i] + "";
to
var sql = "DELETE FROM Commands WHERE commandName = '" + listBox1.SelectedItems[i] + "'";
First thing is first, always always, always use parameterised queries. No exceptions. Ever.
Next, use using blocks for objects that implement iDisposable, to ensure your unmanaged resources are properly cleaned up.
Finally, when removing items from the a collection you should to iterate in reverse to ensure you don't skip over any items:
private void btnRemoveCommand_Click(object sender, EventArgs e)
{
for (int i = listBox1.SelectedItems.Count; i >= 0; i--)
{
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand("DELETE FROM Commands WHERE commandName = #Command;", connection))
{
connection.Open();
//Add parameter with Add method - you may need to address the data type
command.Parameters.Add("#Command", SqlDbType.VarChar, 50).Value = listBox1.SelectedItems[i];
command.ExecuteNonQuery();
}
listBox1.Items.Remove(listBox1.SelectedItems[i]);
}
}
This is still not ideal, because if you have 1000 items, you are executing 1000 queries. My preferred way of doing this is with table valued parameters. The first step would be to create a table type in the database. I tend to use generic naming for ease of reuse:
CREATE TYPE dbo.ListOfString AS TABLE (Value NVARCHAR(MAX));
Then you can pass this type to your query to delete the records
private void btnRemoveCommand_Click(object sender, EventArgs e)
{
var table = new DataTable();
table.Columns.Add("Value", typeof(string));
for (int i = listBox1.SelectedItems.Count; i >= 0; i--)
{
table.Rows.Add(new []{listBox1.SelectedItems[i]});
listBox1.Items.Remove(listBox1.SelectedItems[i]);
}
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand("DELETE FROM Commands WHERE commandName IN (SELECT Value FROM #Commands);", connection)
{
connection.Open();
command.Parameters.Add(new SqlParameter("#Commands", SqlDbType.Structured) { Value = table, TypeName = "dbo.ListOfInt" });
command.ExecuteNonQuery();
}
}
Now you send a single command to the database, which is more efficient than sending multiple commands.
Related
Below here is my code to Retrieve Auto Increment ID After Inserting data into database.
However, I am getting Auto Increment ID before Inserting data into database.
How can I get auto increment ID after insert into database?
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
RetrievePRReqID();
}
}
//Retrieve ID method
private void RetrievePRReqID()
{
try
{
string query = "Select IDENT_CURRENT('tblPRRequest')";
if (sqlCon.State == ConnectionState.Closed)
{
sqlCon.Open();
}
SqlCommand cmd = new SqlCommand(query, sqlCon);
SqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
int value = int.Parse(reader[0].ToString()) ;
txt_PRNO.Text = value.ToString();
}
}
catch(Exception)
{
throw;
}
finally
{
if(con.State == ConnectionState.Open)
{
con.Close();
}
}
}
//Request button Method
protected void btn_Request(object sender, EventArgs e)
{
string insertCmd = "INSERT INTO tblPRRequest (RequestTo,RequestFrom,RequestedByName) " +
"VALUES (#RequestTo,#RequestFrom,#RequestedByName)";
using (SqlConnection conn = new SqlConnection(cs))
{
conn.Open();
using (SqlCommand sqlcmd = new SqlCommand(insertCmd, conn))
{
sqlcmd.Parameters.Clear();
SqlCommand sqlCmd = new SqlCommand(insertCmd, sqlCon);
sqlcmd.Parameters.AddWithValue("#RequestTo", lblPurchasingDept.Text);
sqlcmd.Parameters.AddWithValue("#RequestFrom", ddlDept.SelectedItem.Text);
sqlcmd.Parameters.AddWithValue("#RequestedByName", SUserName.Text);
sqlcmd.ExecuteNonQuery();
}
}
***//After Insert into the table, I want to retrieve latest generated Auto Increment ID in here.***
}
By referring sample answer from #Mx.Wolf, I modified a bit to get the right answer, below here is the codes that is working :
protected void btn_Request(object sender, EventArgs e)
{
object id ;
string insertCmd = "INSERT INTO tblPRRequest (RequestTo,RequestFrom,RequestedByName) " +
"output inserted.PRReqID " +
"VALUES (#RequestTo,#RequestFrom,#RequestedByName)";
using (SqlConnection conn = new SqlConnection(cs))
{
conn.Open();
using (SqlCommand sqlcmd = new SqlCommand(insertCmd, conn))
{
sqlcmd.Parameters.AddWithValue("#RequestTo", lblPurchasingDept.Text);
sqlcmd.Parameters.AddWithValue("#RequestFrom", ddlDept.SelectedItem.Text);
sqlcmd.Parameters.AddWithValue("#RequestedByName", SUserName.Text);
id = sqlcmd.ExecuteScalar(); //the result is of Object type, cast it safely
}
}
Debug.WriteLine(id.ToString()); // Access it like this
As stated in SQL Server documentation
https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-ver15
The OUTPUT clause may be useful to retrieve the value of identity or computed columns after an INSERT or UPDATE operation.
You have to change your SQL statement
INSERT INTO tblPRRequest (RequestTo,RequestFrom,RequestedByName)
OUTPUT inserted.ID
-------^^^^^^^^_^^
VALUES (#RequestTo,#RequestFrom,#RequestedByName)
and now you can use ExecuteScalar to get the inserted value
protected void btn_Request(object sender, EventArgs e)
{
int id= 0;
string insertCmd = "INSERT INTO tblPRRequest (RequestTo,RequestFrom,RequestedByName) " +
"output inserted.ID" +
"VALUES (#RequestTo,#RequestFrom,#RequestedByName)";
using (SqlConnection conn = new SqlConnection(cs))
{
conn.Open();
using (SqlCommand sqlcmd = new SqlCommand(insertCmd, conn))
{
sqlcmd.Parameters.AddWithValue("#RequestTo", lblPurchasingDept.Text);
sqlcmd.Parameters.AddWithValue("#RequestFrom", ddlDept.SelectedItem.Text);
sqlcmd.Parameters.AddWithValue("#RequestedByName", SUserName.Text);
id = (int)sqlcmd.ExecuteScalar(); //the result is of Object type, cast it safely
}
}
Debug.WriteLine(id.ToString()); // Access it like this
}
Try this:
protected void btn_Request(object sender, EventArgs e)
{
string insertCmd = "INSERT INTO tblPRRequest (RequestTo,RequestFrom,RequestedByName) " +
"VALUES (#RequestTo,#RequestFrom,#RequestedByName)";
using (SqlConnection conn = new SqlConnection(cs))
{
conn.Open();
using (SqlCommand sqlcmd = new SqlCommand(insertCmd, conn))
{
sqlcmd.Parameters.Clear();
SqlCommand sqlCmd = new SqlCommand(insertCmd, sqlCon);
sqlcmd.Parameters.AddWithValue("#RequestTo", lblPurchasingDept.Text);
sqlcmd.Parameters.AddWithValue("#RequestFrom", ddlDept.SelectedItem.Text);
sqlcmd.Parameters.AddWithValue("#RequestedByName", SUserName.Text);
sqlcmd.Parameters.Add("#ID", SqlDbType.Int).Direction = ParameterDirection.Output;
sqlcmd.ExecuteNonQuery();
}
}
***//After Insert into the table, I want to retrieve latest generated Auto Increment ID in here.***
sqlcmd.Parameters["#ID"].value; // Access it like this
}
In case you can chage the ExecuteNonQuery to ExecuteScalar, then it would be even easier: What is the difference between ExecuteScalar, ExecuteReader and ExecuteNonQuery?
I am currently writing a piece of code where the user is supposed to insert a few information about an employee and press one button populate for populating a gridview and another one to save the information in gridview into a local database. While running the what I wrote so far there is a consistent error saying "SqlExeption was unhandled by the user code. I have been trying to fix it but without success. It complains on conn.Open();
This is that specific piece of code:
protected void SaveButton_Click(object sender, EventArgs e)
{
string StrQuery;
try
{
using (SqlConnection conn = new SqlConnection(#"Data Source = C:\EmployeeWebProject\EmployeeWebProject\App_Data\EmployeeDatabase.sdf"))
{
using (SqlCommand comm = new SqlCommand("SELECT * FROM Employee"))
{
comm.Connection = conn;
conn.Open();
for (int i = 0; i < GridView1.Rows.Count; i++)
{
StrQuery = #"INSERT INTO Employee VALUES ("
+ GridView1.Rows[i].Cells[0].ToString() + ", "
+ GridView1.Rows[i].Cells[1].ToString() + ", "
+ GridView1.Rows[i].Cells[2].ToString() + ", "
+ GridView1.Rows[i].Cells[3].ToString() + ", "
+ GridView1.Rows[i].Cells[4].ToString() + ");";
comm.CommandText = StrQuery;
comm.ExecuteNonQuery();
}
}
}
}
finally
{
}
}
To avoid SQL injection and use properly parametrized queries, and also use the SQL Server CE connection and command objects, try this code:
protected void SaveButton_Click(object sender, EventArgs e)
{
string StrQuery;
try
{
// define connection string and INSERT query WITH PARAMETERS
string connectionString = #"Data Source = C:\EmployeeWebProject\EmployeeWebProject\App_Data\EmployeeDatabase.sdf";
string insertQry = "INSERT INTO Employees(Col1, Col2, Col3, Col4, Col5) " +
"VALUES(#Col1, #Col2, #Col3, #Col4, #Col5);";
// define connection and command for SQL Server CE
using (SqlCeConnection conn = new SqlCeConnection(connectionString))
using (SqlCeCommand cmd = new SqlCeCommand(insertQry, conn))
{
// add parameters to your command - adapt those *as needed* - we don't know your table structure,
// nor what datatype (and possibly length) those parameters are !
cmd.Parameters.Add("#Col1", SqlDbType.Int);
cmd.Parameters.Add("#Col2", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#Col3", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#Col4", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#Col5", SqlDbType.VarChar, 100);
conn.Open();
for (int i = 0; i < GridView1.Rows.Count; i++)
{
// set parameter values
cmd.Parameters["#Col1"].Value = Convert.ToInt32(GridView1.Rows[i].Cells[0]);
cmd.Parameters["#Col2"].Value = GridView1.Rows[i].Cells[1].ToString();
cmd.Parameters["#Col3"].Value = GridView1.Rows[i].Cells[1].ToString();
cmd.Parameters["#Col4"].Value = GridView1.Rows[i].Cells[1].ToString();
cmd.Parameters["#Col5"].Value = GridView1.Rows[i].Cells[1].ToString();
cmd.ExecuteNonQuery();
}
}
}
finally
{
}
}
I want to insert a string list of device name and related seq number into a table on SQL server 2014. The IDE is Visual Studio 2015, the programming language is C#.
When I run the program and click the button14, the error is:
The parameterized query '(#ID int,#NAME nvarchar(4000),#RSSI int)INSERT BeaconInfo (ID, N' expects the parameter '#NAME', which was not supplied.
I am not sure my codes of inserting sql is correct or not.
public partial class Form1 : Form
{
int seqnumber = 333;
List<string> items;
string tmp_name;
BluetoothDeviceInfo[] devices;
public Form1()
{
items = new List<string>();
InitializeComponent();
}
private void startScan()
{
listBox1.DataSource = null;
listBox1.Items.Clear();
items.Clear();
Thread bluetoothScanThread = new Thread(new ThreadStart(scan));
bluetoothScanThread.Start();
}
private void scan()
{
updateUI("Starting Scan..");
BluetoothClient client = new BluetoothClient();
devices = client.DiscoverDevicesInRange();
updateUI("Scan complete");
updateUI(devices.Length.ToString() + " devices discovered");
foreach (BluetoothDeviceInfo d in devices)
{
items.Add(d.DeviceName);
}
updateDeviceList();
}
private void button14_Click(object sender, EventArgs e)
{
System.Data.SqlClient.SqlConnection sqlConnection1 = new System.Data.SqlClient.SqlConnection("....");
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "INSERT BeaconInfo (ID, Name, RSSI) VALUES (#ID, #NAME, #RSSI)";
cmd.Parameters.AddWithValue("#ID", seqnumber);
cmd.Parameters.AddWithValue("#NAME", tmp_name);
cmd.Parameters.AddWithValue("#RSSI", 55);
cmd.Connection = sqlConnection1;
for (int j = 0; j < items.Count; j++)
{
seqnumber = seqnumber + 1;
tmp_name = items[j];
sqlConnection1.Open();
cmd.ExecuteNonQuery();
sqlConnection1.Close();
}
}
Please try to change your code like this:
private void button14_Click(object sender, EventArgs e)
{
using (System.Data.SqlClient.SqlConnection sqlConnection1 = new System.Data.SqlClient.SqlConnection("...."))
{
sqlConnection1.Open();
for (int j = 0; j < items.Count; j++)
{
seqnumber = seqnumber + 1;
tmp_name = items[j];
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand())
{
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "INSERT BeaconInfo (ID, Name, RSSI) VALUES (#ID, #NAME, #RSSI)";
cmd.Parameters.AddWithValue("#ID", seqnumber);
cmd.Parameters.AddWithValue("#NAME", tmp_name);
cmd.Parameters.AddWithValue("#RSSI", 55);
cmd.Connection = sqlConnection1;
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
//Here handle if error
}
}
}
}
}
Generaly is not good practice to write sql statements in handlers, so at Form qctually. It would be better to create class doing this operation, and call it inside handler.
Please note as comments under your question suggested, tmp_name is not set and parameters at SqlClient are not references so changing value after association to variable tmp_name has not any impact on value of parameters.
Hey everyone pretty new to SQL Database functions but have been coding in c# for about a year now still not that great at it but I'm getting there!
I'm currently creating a football application and to Edit players and Matches i was wanting to use one drop down combo box to retrieve data from an SQL database which then would populate other text boxes and combo boxes. I've had a go at it myself but don't know where i'm going wrong.
On form load my connection opens i populate my datasets and i execute this method to populate my combobox
private void Navigate()
{
string showPlayers = "SELECT * From Add_Players";
SqlCommand cmdData = new SqlCommand(showPlayers, conn);
SqlDataReader myReader = cmdData.ExecuteReader();
while (myReader.Read())
{
comboEditPlayer.Items.Add(myReader[0]);
}
conn.Close();
}
After which in the combo box selected index changed method i have this code
private void comboEditPlayer_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
conn.Open();
string showPlayers = "SELECT * From Add_Players WHERE Player_ID ='"
+ comboEditPlayer + "' ;";
SqlCommand cmdData = new SqlCommand(showPlayers, conn);
SqlDataReader myReader = cmdData.ExecuteReader();
while (myReader.Read())
{
comboEditPlayerPos.Items.Add(myReader[1]);
txtEditPlayerName.Text = myReader[2].ToString();
txtEditPlayerSecond.Text = myReader[3].ToString();
comboEditPlayerStatus.Items.Add(myReader[4]);
}
conn.Close();
conn.Dispose();
}
catch (Exception comboFail)
{
MessageBox.Show(comboFail.ToString());
}
}
I've been told this code is open and i need to use parameterized queries for preventing hacker attempts which i have started but do not know what Parameter i should be adding to the code i have for this is below
private void comboEditPlayer_SelectedIndexChanged(object sender, EventArgs e)
{
string connectionString =
ZimbFootball.Properties.Settings.Default.Football2ConnectionString;
using (SqlConnection connection = new SqlConnection (connectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(
"SELECT * From Add_Players WHERE Player_ID ="
+ comboEditPlayer.SelectedValue + "", connection))
{
command.Parameters.Add(new SqlParameter ("",));
}
}
}
All help is appreciated and please go easy on me :P
You could add a parameter to the collection with the value of your ComboBox, then execute the query and read back the values from the reader
private void comboEditPlayer_SelectedIndexChanged(object sender, EventArgs e)
{
string connectionString =
ZimbFootball.Properties.Settings.Default.Football2ConnectionString;
using (SqlConnection connection = new SqlConnection (connectionString))
using (SqlCommand command = new SqlCommand(
"SELECT * From Add_Players WHERE Player_ID =#id", connection))
{
connection.Open();
command.Parameters.AddWithValue("#id", comboEditPlayer.Text);
using(SqlDataReader myReader = command.ExecuteReader())
{
while (myReader.Read())
{
comboEditPlayerPos.Items.Add(myReader[1]);
txtEditPlayerName.Text = myReader[2].ToString();
txtEditPlayerSecond.Text = myReader[3].ToString();
comboEditPlayerStatus.Items.Add(myReader[4]);
}
}
}
}
I have a ListView. It has 6 columns:
question_id | question_text | start_time | end_time | status | repeat
respectively. Right now I am able to display the data from the database. This is my code:
private void Voting_Editor_Tool_Load(object sender, EventArgs e)
{
GetData();
}
public void GetData()
{
try
{
now = DateTime.Now;
String time_date = now.ToString();
myConnection = new SqlConnection(#"User ID=sa;Password=password123;Initial Catalog=dishtv;Persist Security Info=True;Data Source=ENMEDIA-EA6278E\ENMEDIA");
//myConnection.Open();
//SqlDataReader dr = new SqlCommand("SELECT question_text,question_id FROM otvtbl_question ", myConnection).ExecuteReader();
// listView1.Columns.Clear();
listView1.Items.Clear();
myConnection.Open();
String MyString1 = string.Format("SELECT question_id,question_text,start_time,end_time,status,repeat FROM otvtbl_question");
com = myConnection.CreateCommand();
com.CommandText = MyString1;
dr = com.ExecuteReader();
ListViewItem itmX;
//Adding the Items To The Each Column
while (dr.Read())
{
itmX = new ListViewItem();
itmX.Text = dr.GetValue(0).ToString();
var word = itmX.Text;
for (int i = 1; i < 6; i++)
{
itmX.SubItems.Add(dr.GetValue(i).ToString());
}
if (dr.GetDateTime(2) < now && dr.GetDateTime(3) > now)
{
itmX.SubItems[4].Text = "Broadcasting";
}
else if (dr.GetDateTime(3) < now)
{
string a=Convert.toString(dr.GetDateTime(3));
itmX.SubItems[4].Text = "Expired";
String broadcast = string.Format("UPDATE otvtbl_question SET status='EXPIRED' where start_time='{6}'",a );
//Execute the SqlCommand
com = new SqlCommand(broadcast, myConnection);
com.ExecuteNonQuery();
}
else
{
itmX.SubItems[4].Text = "Not Expired";
}
listView1.Items.Add(itmX);
}
dr.Close();
myConnection.Close();
}
catch (Exception ex)
{
//Error Message While Fetching
MessageBox.Show("Error While Fetching the data From the DataBase" + ex);
}
finally
{
//Closing The Connection
if (dr != null)
dr.Close();
if (myConnection.State == ConnectionState.Open)
myConnection.Close();
}
}
In this code the status column has to be updated every time the user load the form. While the form is loading it has to check the whether the start_time is greater than current time. If it is greater than the status column has to display NOT EXPIRED otherwise it has to show EXPIRED. The problem is that I am able to show the EXPIRED and NOT EXPIRED values in Status column by comparing the time, but I want to save the EXPIRED and NOT EXPIRED values in the database while it shows the values in the status column. I have tried to update it using following command:
String broadcast = string.Format("UPDATE otvtbl_question SET status='EXPIRED' where start_time='{6}'",a );
//Execute the SqlCommand
com = new SqlCommand(broadcast, myConnection);
com.ExecuteNonQuery();
But it says:
DataReader has to be closed before Updating the data.
I even tried to close the datareader and tried to update and it says different errors as:
Index (zero based) must be greater than or equal to zero and less than size of the argument list
Any suggestions?
You should implement the using statement. This will resolve the issue. Following are the blocks where the using statement should be implemented.
Sql Connection
DataReader
Moreover we should use parameterized queries. Below is the sample code.
using (System.Data.SqlClient.SqlConnection con = new SqlConnection("YourConnection string")) {
con.Open();
SqlCommand cmd = new SqlCommand();
string expression = "Parameter value";
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "Your Stored Procedure";
cmd.Parameters.Add("Your Parameter Name",
SqlDbType.VarChar).Value = expression;
cmd.Connection = con;
using (IDataReader dr = cmd.ExecuteReader())
{
if (dr.Read())
{
}
}
}
Here is the IDisposable example as requested by you.
IDisposable