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.
Related
I've been trying to create a function that will set up an order for all the items that are lacking in my inventory.
RequiredStockForAllOrders basically assigns a value to each object in stockItems which lets me know how many items I need to order.
I checked with a messagebox which does the change in values (both ID and quantity) but when I run the loop that is supposed to insert each product with its respective quantity I only insert 1 product n times where n is the amount of items in the list.
private void AddAllRequiredItems_Click(object sender, EventArgs e)
{
var stockItems = new List<MyData>();
//MyData is an object with a productID int and a productQuantity int
RequiredStockForAllOrders(stockItems);
//determining the quantity required for each item
OleDbConnection con = new OleDbConnection(DatabaseConnectionString);
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = con;
con.Open();
string sql2 = "INSERT INTO restockingDetails(RestockingID,ProductID,Quantity,Shop_ID) values (#restockingID,#productID,#quantity,#shop_id)";
cmd.CommandText = sql2;
int i = 0;
while (i < stockItems.Count)
{
try
{
MessageBox.Show(stockItems[i].productId.ToString()); //For testing
cmd.Parameters.AddWithValue("#restockingID", restockingOrder);
cmd.Parameters.AddWithValue("#productID", stockItems[i].productId);
cmd.Parameters.AddWithValue("#quantity", stockItems[i].productQuantity);
cmd.Parameters.AddWithValue("#shop_id", shopIDGlobal);
cmd.ExecuteNonQuery();
MessageBox.Show(" Item added to list"); //for testing
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
i = i + 1;
}
con.Close()
}
Just add this line before adding the parameters
MessageBox.Show(stockItems[i].productId.ToString()); //For testing
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#restockingID", restockingOrder);
You actual code continues to add parameters to the command collection, but the query uses only the first four. With other providers this code will result in an error (too many parameters) but OleDb is somebit limited in this point. Probably because it doesn't recognize parameters by their name, but by their position
A better approach could be to define the parameters just once and then updating their values inside the loop
private void AddAllRequiredItems_Click(object sender, EventArgs e)
{
var stockItems = new List<MyData>();
RequiredStockForAllOrders(stockItems);
string sql2 = "INSERT INTO restockingDetails(RestockingID,ProductID,Quantity,Shop_ID) values (#restockingID,#productID,#quantity,#shop_id)";
using(OleDbConnection con = new OleDbConnection(DatabaseConnectionString))
using(OleDbCommand cmd = new OleDbCommand(sql2, con))
{
con.Open();
cmd.Parameters.Add("#restockingID", OleDbType.Integer);
cmd.Parameters.Add("#productID", OleDbType.Integer);
cmd.Parameters.Add("#quantity", OleDbType.Integer);
cmd.Parameters.Add("#shop_id", OleDbType.Integer);
foreach(MyData item in stockItems)
{
try
{
cmd.Parameters["#restockingID"].Value = restockingOrder;
cmd.Parameters["#productID"].Value = item.productId;
cmd.Parameters["#quantity"].Value = item.productQuantity;
cmd.Parameters["#shop_id"].Value = shopIDGlobal;
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
create the command into the while loop :
OleDbConnection con = new OleDbConnection(DatabaseConnectionString);
OleDbCommand cmd;
string sql2 = "INSERT INTO restockingDetails(RestockingID,ProductID,Quantity,Shop_ID) values (#restockingID,#productID,#quantity,#shop_id)";
int i = 0;
while (i < stockItems.Count)
{
try
{
MessageBox.Show(stockItems[i].productId.ToString()); //For testing
cmd = new OleDbCommand();
cmd.Connection = con;
con.Open();
cmd.CommandText = sql2;
cmd.Parameters.AddWithValue("#restockingID", restockingOrder);
cmd.Parameters.AddWithValue("#productID", stockItems[i].productId);
cmd.Parameters.AddWithValue("#quantity", stockItems[i].productQuantity);
cmd.Parameters.AddWithValue("#shop_id", shopIDGlobal);
cmd.ExecuteNonQuery();
MessageBox.Show(" Item added to list"); //for testing
con.Close()
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
i = i + 1;
}
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.
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 have the following code and I want to show an error message if the id is not found in the table can any body help?
private void button4_Click(object sender, EventArgs e)
{
conn = new MySqlConnection(cs);
string sql = "select * from question where id=#id;";
MySqlCommand cmd = new MySqlCommand(sql, conn);
conn.Open();
cmd.Prepare();
cmd.Parameters.AddWithValue("#id", int.Parse(textBox1.Text));
MySqlDataReader rd = cmd.ExecuteReader();
string res = "";
while (rd.Read())
{
if (rd.HasRows==true)
{
res = string.Format("id={0} pid={1} question={2}", rd.GetInt32(0), rd.GetInt32(1), rd.GetString(2));
MessageBox.Show("found" + "\n" + res);
}
MessageBox.Show(" id not found");
}
You need to check for has rows before to start iterating the reader.
if (rd.HasRows==true)
{
while (rd.Read())
{
// Do something here
}
}
else
{
// Show message here
}
private void Save_Click(object sender, EventArgs e)
{
string strconn = #"Server=.\SQLEXPRESS;initial catalog=PharmacyV2;integrated security=true;";
SqlConnection conn = new SqlConnection(strconn);
//SqlCommand cmd = new SqlCommand();
DataSet ds = new DataSet();
conn.Open();
SqlDataAdapter da = new SqlDataAdapter("select * from Units",conn);
da.Fill(ds, "Units");
bool found = false;
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
for (int j = 0; j < ds.Tables["Units"].Rows.Count; j++)
{
if (ds.Tables["Units"].Rows[j][0].ToString() == dataGridView1.Rows[i].Cells[0].Value.ToString())
{
found = true;
break;
}
}
if (found==false)
{
SqlCommand cmd;
cmd = new SqlCommand("insert into Units (Unit_name) values (#name)", conn);
cmd.Parameters.AddWithValue("#name", dataGridView1.Rows[i].Cells[0].Value.ToString());
cmd.ExecuteNonQuery();
MessageBox.Show("تمت الاضافه");
}
}
conn.Close();
}
my program compare the each element from datagridview with every element from Uint table from database to prevent duplicate in database
if element from datagridvoew is not Similar to element in uint table in database
implement insert statement
Why the program does not insert any data to database?
(Does not implement the insert statement )
initialise your found variable to false inside your first for loop :
found = false;
so that it will be set to initial state for every iteration. otherwise if once it is set to true always becomes true.thats why yor insert statement is not getting executed.
So your for loop should look like :
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
found = false;
for (int j = 0; j < ds.Tables["Units"].Rows.Count; j++)
{
if (ds.Tables["Units"].Rows[j][0].ToString() == dataGridView1.Rows[i].Cells[0].Value.ToString())
{
found = true;
break;
}
}
if (found==false)
{
SqlCommand cmd;
cmd = new SqlCommand("insert into Units (Unit_name) values (#name)", conn);
cmd.Parameters.AddWithValue("#name", dataGridView1.Rows[i].Cells[0].Value.ToString());
cmd.ExecuteNonQuery();
MessageBox.Show("تمت الاضافه");
}
}
How about you ask the database to check if the entry exists?
var unitName = dataGridView1.Rows[i].Cells[0].Value.ToString();
var command = new SqlCommand("SELECT COUNT(*) FROM Units WHERE Unit_name = #name", connection);
command.Parameters.AddWithValue("#name", unitName);
int result = (int)command.ExectureScalar();
if(result == 0) // no entry
{
//Insert.
}