Update single cell in datagrid WPF - c#

I have a datagrid in my WPF application. In one column I have an int (column name = Amount).
So for example there will be a number "4" in the cell. I can edit "4" in the DataGrid to "3".
After editing, I will push the button "Update" so my database column Amount will be updated.
It is working, but it update all the cells in the column Amount to the Id number of the chosen row.
This is my code in the xaml.cs file:
private void Update(object sender, RoutedEventArgs e)
{
DataRowView o = (DataRowView)g2.SelectedItem;
int Amount = Convert.ToInt32(o.Row.ItemArray[0]);
try
{
const string query = #"UPDATE [Stock] SET [STOCK].Amount = #Aantal;";
using (SqlConnection con = new SqlConnection("Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=\"...."))
using (SqlCommand cmd = new SqlCommand(query, con))
{
cmd.Parameters.Add("#Amount", SqlDbType.Int).Value = Amount;
con.Open();
cmd.ExecuteNonQuery();
}
MessageBox.Show("Update complete");
binddatagrid();
}
catch (Exception ex)
{
MessageBox.Show("Error occurred:\r\n" + ex.Message);
}
}
What am I doing wrong?

Your database query is updating the Amount column in every row in the [Stock] table. You need to add a WHERE clause to your database query so that you only update the [Stock] row in the database that corresponds to the selected row in the DataGrid.
I don't know what your database schema looks like, but I'm assuming that the [Stock] table has an Id column. If so, the query might look something like this:
UPDATE [Stock] SET [Stock].Amount = #Anatal WHERE [Stock].Id = #Id
Notice that the query now has a second parameter, #Id. That means that you'll need to get the Id from the selected row in much the same way that you're currently getting the Amount.
int id = Convert.ToInt32(o.Row.ItemArray[1]);
I used o.Row.ItemArray[1], but I don't know what index the Id will actually be stored at. You'll have to use that index to get the correct Id.
Since your query has a second parameter, you also need to add it to the Parameters collection of the SqlCommand instance. Just like how you're doing with Amount.
cmd.Parameters.Add("#Id", SqlDbType.Int).Value = id;

Related

Updating a database from selected row in another form

I am having issues updating a selected row on a datagridview that pulls from a database in another form.
I used this to get the information from the datagridview into the textboxes on the other form:
private void updateAppointmentButton_Click(object sender, EventArgs e)
{
UpdateAppointment updateAppointment = new UpdateAppointment();
updateAppointment.mainFormObject = this;
updateAppointment.customerIdBox.Text = appointmentCalendar.CurrentRow.Cells[0].Value.ToString();
updateAppointment.customerNameBox.Text = appointmentCalendar.CurrentRow.Cells[1].Value.ToString();
updateAppointment.typeBox.Text = appointmentCalendar.CurrentRow.Cells[2].Value.ToString();
updateAppointment.startTimeBox.Value = Convert.ToDateTime(appointmentCalendar.CurrentRow.Cells[4].Value.ToString());
updateAppointment.endTimeBox.Value = Convert.ToDateTime(appointmentCalendar.CurrentRow.Cells[3].Value.ToString());
updateAppointment.Show();
MySqlConnection c = new MySqlConnection(SqlUpdater.conString);
MySqlCommand updateCmd = new MySqlCommand();
updateCmd.Connection = c;
c.Open();
updateCmd.CommandText = $"UPDATE customer SET customerName = '{customerNameBox.Text}'";
updateCmd.ExecuteNonQuery();
c.Close();
MessageBox.Show("Appointment Updated");
I figure its the SQL query, but not sure how to limit it to JUST the information on the selected row. Right now, it'll update everyone on the datagridview and database.
Any ideas?
Thanks!
I've tried putting
MainForm.appointmentCalendar.CurrentRow.Cells[1].Value.ToString();
as WHERE in the SQL query, but it returns an "object reference is required" error.
have a column with unique customer ID, then in your query you want
Update customer SET customerName = '{customerNameBox.Text}' where customerID = 'UniqueID'
----- (whatever the ID that you are trying to update is)
probably something like int.Parse(otherDataGrid.selectedRows[0].Cells["ID"].Value.ToString())
#edit
I don't really understand what you're trying to say. You might want to try with parameteres. this would be your query:
Update appointment set type = #type, start = #start, end = #end where customerId = #id
then before you execute the command you say:
updateCmd.Parameters.AddWithValue("#type", typeBox.Text);
and do that for all other parameters too.
Also make sure that your text boxes are not empty, because they most likely are if your query is deleting the data (maybe it's updating it with an empty string)

Updating SQLite DB from DGV (C#)

On one form I have a dgv. From another form, I can add an item to the dgv and also place the new item into the SQLite database.
What I'm trying to do is also be able to edit the item from the dgv, and have the edit be saved in the database also.
I have this code for CellEndEdit event:
SetConnection();
sqlconnection.Open();
this.dataGridView1.Rows[e.RowIndex].Selected = true;
this.rowIndex1 = e.RowIndex;
this.dataGridView1.CurrentCell = this.dataGridView1.Rows[e.RowIndex].Cells[0];
sqlcmd = new SQLiteCommand("UPDATE table1 SET item = #item, quantity = #quantity WHERE id= " + this.dataGridView1.Rows[this.rowIndex1].Cells["id"].Value, sqlconnection);
sqlcmd.Parameters.AddWithValue("#item", this.dataGridView1.Rows[this.rowIndex1].Cells["item1"].Value);
sqlcmd.Parameters.AddWithValue("#quantity", this.dataGridView1.Rows[this.rowIndex1].Cells["quantity1"].Value);
sqlcmd.ExecuteNonQuery();
sqlconnection.Close();
This code works, but only if I load the database to the dgv.
When the program is first opened, the database isn't loaded into the dgv. The problem I run into, is when I add a new item (and its the only item present in the dgv), and I try to edit it (aka. change name.etc.), I get the following error: SQL logic error or missing database
near " ": syntax error
Note: When the dgv is empty and I add a new item, the new item is successfully added to the database table.
Also Note: 'id' is the PRIMARY KEY and AUTOINCREMENTed
The situation you're having here is that when you add a new item to the DGV, you are not providing a value to the ID column. So at the end of the query
"UPDATE table1 SET item = #item, quantity = #quantity WHERE id= " + this.dataGridView1.Rows[this.rowIndex1].Cells["id"].Value
This will become like id = . because the ID column in the DGV is currently empty and is definitely a Syntax Error.
It works when you load data because, you are filling up this column. So the solution is to provide value to the ID column properly when you insert a new item.
After inserting an entry to the db, get the Automatically Incremented ID by using a query
Select last_insert_rowid();
Read the value using reader and apply it to the ID column of the table
This works for me.
private void btnUpdate_Click(object sender, EventArgs e)
{
using (SqlConnection con = new SqlConnection("Server=your_server_name;Database=your_db_name;Trusted_Connection=True;"))
{
using (SqlCommand cmd = new SqlCommand("SELECT * FROM Courses", con))
{
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
{
SqlCommandBuilder sqlcmd = new SqlCommandBuilder(da);
DataSet ds = new System.Data.DataSet(); // remove this line
da.Update(this.ds, "Courses");
}
}
}
}
}

SQL ExecuteNonQuery for Multiple rows

I have a table("Product_Location") with the following columns:
ProductID (PK), LocationID (PK), Quantity
i would like to update the table in the database from rows in a datatable. if row already exists then Update quantity otherwise Insert new row.
i have the following method which update the quantity in the table, if the combination of productID and LocationID exists, it just update otherwise insert new row for that combination. code:
public bool UpdateLocationQuantity(DataSet productLocationData,
SqlTransaction sqlTransaction)
{
try
{
bool result = true;
SqlCommand command = new SqlCommand();
//get the Transaction table which contains rows to update from dataset
DataTable table = productLocationData.Tables["Inventory_Transactions"];
//Create Command Text
string commandText = #" IF Exists (SELECT * FROM Product_Location PL
WHERE ProductID = #ProductID AND LocationID = #LocationID)
UPDATE Product_Location SET Quantity = Quantity + #Quantity
WHERE ProductID = #ProductID AND LocationID = #LocationID
ELSE
INSERT INTO Product_Location (ProductID,LocationID,Quantity)
VALUES(#ProductID,#LocationID,#quantity)";
command = new SqlCommand(commandText, this.CurrentConnection);
command.CommandType = CommandType.Text;
command.Transaction = sqlTransaction;
SqlParameterCollection paramCols = command.Parameters;
//this loop will do the update or insert for all rows in the table
// How can we optimize to only ONE CALL to database?
foreach (DataRow row in table.Rows)
{
paramCols.Clear();
paramCols.AddWithValue("#ProductID",row["ProductID"]);
paramCols.AddWithValue("#LocationID", row["LocationID"]);
paramCols.AddWithValue("#Quantity", row["Quantity"]);
result &= command.ExecuteNonQuery()>= 0;
}
return result;
}
catch
{
throw;
}
}
**My question is how we can optimize the code so only one call to ExecuteNonQuery to update the database instead of having it in a loop? Please note that we are not using StoredProcedure and all should be from C# and SQL Queries or Transactions.
if it was just Update the rows, we could call command.Update with providing the source table and it easily update all the rows without using rows. but since i am using 'IF Exists' then we are forced to use ExecuteNonQuery which is not accepting source table as parameter.
Thank You
Instead of using a ParameterCollection you could do:
command.Parameters.Add(new SqlParameter("#ProductID", ProductData.PRODUCTID_FIELD));
or
command.Parameters.AddWithValue("#ProductID", ProductData.PRODUCTID_FIELD);
and so on. You don't actually have to specify the type.
Then call:
int numOfRowsAffected = command.ExecuteNonQuery();
There is no dataset to be returned, only the number of rows affected, since this is a non-query.
The problem with making a ParameterCollection like you are doing is you then need to set command.Parameters = paramCols; but command.Parameters is Read-Only, so you can't. That is, its read-only as far as assignment goes. You can only add parameters to it through the methods Add and AddWithValue.
for multiple rows , add command in loop
foreach (DataRow row in table.Rows)
{
SqlCommand command = new SqlCommand();
.
.
.
}

Search-Filtering GridView control results in no records found

I'm trying to filter-search the data from a GridView control which is bound to a SQL data connection but i'm not having any success. Whenever I try to search for something, it results in no records found. Here is my main searching code:
public void FilterGridView(string column, string terms) //SELECT * FROM [Table_1] WHERE [First Name] LIKE '%valuetosearchfor%' is the format to use here
{
DataTable filterTable = new DataTable(); //create a datatable to hold the data while we retrieve it
SqlConnection connection = new SqlConnection("Data Source=TAMUWINPART\\SQLEXPRESS;Initial Catalog=phpMyWorkers;Integrated Security=True"); //connect to SQL
try
{
connection.Open(); //open the connection
string filterStatement = "SELECT * FROM [Table_1] WHERE #column LIKE '%#terms%'"; //select all from table_1 with the correct column name / terms
SqlCommand sqlCmd = new SqlCommand(filterStatement, connection); //make a sql command
sqlCmd.CommandType = CommandType.Text; //make it an average joe sql text command
//define the # sql variables
sqlCmd.Parameters.AddWithValue("#column", column);
sqlCmd.Parameters.AddWithValue("#terms", terms);
SqlDataAdapter filterAdapter = new SqlDataAdapter(sqlCmd); //make a data adapter to get all the data from the command and put it into the data table
filterAdapter.Fill(filterTable); //fill the data table with the data from the SQL connection
if(filterTable.Rows.Count > 0) //if records were found relating to the terms
{
//if records WERE found
workersView.DataSource = filterTable; //set the data source to this instead
workersView.DataBind(); //refresh the data
}
else
{
//no records were found in this case, do not be an inneficient guy who will refresh the gridview for no reason
FilterSearchTerms.Text = "0 Records Found!"; //notify the user that he/she won't get anything
}
}
catch (System.Data.SqlClient.SqlException ex) //if the thing just decides that it doesn't want to work today
{
string msg = "myWorkers had a problem fetching the data : ";
msg += ex.Message;
throw new Exception(msg);
}
finally
{
connection.Close(); //close the connection
}
}
public void FilterSearchButton_Click(object sender, EventArgs e) //when someone clicks the button to filtersearch the gridviews
{
string column = FilterSearchDropdown.SelectedValue.ToString(); //get the column that the user wants to filter by and make sure it's a string
string terms = FilterSearchTerms.Text; //get the terms to search by - verified string for sure
FilterGridView(column, terms);
}
public void FilterRemoveButton_Click(object sender, EventArgs e) //when someone decides to remove the filter
{
BindGridView(); //refresh the gridview based on all of the data
FilterSearchTerms.Text = ""; //remove the text from the filter search terms box
}
Here is a picture of what the layout looks like.
Even if I search for real data it results in this being called
else
{
//no records were found in this case, do not be an inneficient guy who will refresh the gridview for no reason
FilterSearchTerms.Text = "0 Records Found!"; //notify the user that he/she won't get anything
}
meaning that the datatable's row count is 0...
Does anyone know why? Thank you.
I suspect that your SQL LIKE code is incorrect. Take a look at how to use like with SQL parameter in this question:how-to-get-like-clause-to-work-in-ado-net-and-sql-server. It would also help to display the final sql command text that gets sent to the database.
Replace this line :
string column = FilterSearchDropdown.SelectedValue.ToString();
with this:
string column = FilterSearchDropdown.SelectedText;
Also, you need correct your command string and command parameters as Emmad Kareem suggested in other answer. Your string and parameter should be like below:
string filterStatement = "SELECT * FROM [Table_1] WHERE [{0}] LIKE #terms"; //select all from table_1 with the correct column name / terms
filterStatement = string.Format(filterStatement, column);
.... .... .... .... .... ....
// sqlCmd.Parameters.AddWithValue("#column", column );
sqlCmd.Parameters.AddWithValue("#terms", "%" + terms + "%");
You only need to replace this query:
string filterStatement = "SELECT * FROM [Table_1] WHERE #column LIKE '%"+terms+"%'";
And you should be able to find your data.

Save changes from dataGridView to SQL Server DB

I have a form with dataGridView to display content of table Attendance
TagID SessionID ScanningTime
---------------------------------------
4820427 Test1 14/08/2013 18:12
I would like to add a record manually to the table to look like this....
TagID SessionID ScanningTime
---------------------------------------
4820000 Test1 14/08/2013 18:12
0000001 Test2 15/08/2012 17:00
...and save changes to SQL Server database after button has been clicked.
I have tried creating UPDATE query:
command.Text = "UPDATE Attendance
SET TagID= #tagNo, SessionID= #sessionNo, ScanningTime= #scantime";
But I'm not sure how to assign values from DGV to parameters.
What is the correct way to save changes from dataGridView to SQL Server database?
Please note that I do not use DataSet or TableAdapter when working with DGV.
You're going to want to consume the RowsAdded method of the DataGridView and cache the necessary information to INSERT the data:
// new form field for caching
private List<DataGridViewRow> _addedRowsCache = new List<DataGridViewRow>();
private void dataGridView1_RowsAdded(object sender,
DataGridViewRowsAddedEventArgs e)
{
for (int i = e.RowIndex; i < e.RowIndex + e.RowCount; i++)
{
_addedRowsCache.Add(dataGridView.Rows[i]);
}
}
and then when you're ready to submit the data to the database:
// new class field to store the INSERT sql
private string _insertSQL = "INSERT INTO tbl (field1, field2) VALUES (#field1, #field2)";
// this block goes inside the click event
if (_addedRowsCache.Count > 0)
{
using (SqlConnection c = new SqlConnection(connString))
{
c.Open();
foreach (DataGridViewRow r in _addedRowsCache)
{
using (SqlCommand cmd = new SqlCommand(sql, c))
{
// add any parameter values, I don't know where `val(n)`
// comes from here. Maybe from the `DataBoundItem`
// off the `DataGridViewRow`, or maybe from a `Cell`
// out of the `Cells` collection of the `DataGridViewRow`
cmd.Parameters.AddWithValue("#field1", val1);
cmd.Parameters.AddWithValue("#field2", val2);
cmd.ExecuteNonQuery();
}
}
}
}

Categories