I have asp.net detailsview which inserts data into payment allocation table, however I want to run a update command that update data into s_transaction_enquiry table, which is done in C#. When I run the code, the update command runs first before the insert command so not data is put into the s_transaction_enquiry table.
I have created the update command to run when user click's on the insert button in the details view.
The insert command is linked to the detailview's Sql Data source.
I have been told I can use "IsPostBack" property in the page_load but sure how to do this, is there anyone who could help me??
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string conn = "";
string sqlCOmmand = "UPDATE s_transaction_enquiry, payment_allocation SET s_transaction_enquiry.payment_amount = payment_allocation.payment_amount, s_transaction_enquiry.payment_ref = payment_allocation.payment_ref, s_transaction_enquiry.payment_received_date = payment_allocation.payment_received_date WHERE payment_allocation.s_invoice_numer = s_transaction_enquiry.s_invoice_number AND payment_allocation.account_number = s_transaction_enquiry.account_number";
conn = ConfigurationManager.ConnectionStrings["Conn"].ToString();
UpdateRow(conn, sqlCOmmand);
}
}
public void UpdateRow(string connectionString, string insertSQL)
{
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
OleDbCommand command = new OleDbCommand(insertSQL);
command.Connection = connection;
try
{
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Insert statement from datasource:
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString1 %>" DeleteCommand="DELETE FROM [payment_allocation] WHERE [payment_ref] = ?" ProviderName="<%$ ConnectionStrings:ConnectionString1.ProviderName %>" SelectCommand="SELECT * FROM [payment_allocation]"
InsertCommand="INSERT INTO [payment_allocation] ([payment_ref], [account_number], [account_ref], [allocate_date], [payment_amount], [payment_received_date], [s_invoice_numer]) VALUES (?, ?, ?, ?, ?, ?, ?)">
Button which invokes the insert statement:
<asp:Button ID="Button1" runat="server" CausesValidation="True" CommandName="Insert" Text="Create"/>
you should close your connection after every action. you have opened a connection on 'page_load' but didnt close it, and since page_load executes on every postback as well, which means every time you click your button, you attempt to open a connection again without closing it.
also notice that page_load executes before the button_click event handler therefore every time you click your button you open the connection without closing, and the trying to open it again in the click handler.
OleDbConnection is a disposable object, which means it implements the .dispose() function, which also means that it can be used in a using() statement .
the using() statement creates a new object and disposes of it after.
you have a pretty good explanation on openning/closing/disposing of OleDbConnection in c# here on microsoft website: OleDbConnection Class
basically in order to adapt it to your code, you would want to do something like this,
first put your database handling in a separate function for convenience and call it from page load::
protected void Page_Load(object sender, EventArgs e)
{
string conn = "";
string sqlCOmmand= "inset blablabla into blablabla";
conn = ConfigurationManager.ConnectionStrings["Conn"].ToString();
InsertRow(conn,sqlCOmmand);
}
//taken from microsoft website
public void InsertRow(string connectionString, string insertSQL)
{
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
// The insertSQL string contains a SQL statement that
// inserts a new row in the source table.
OleDbCommand command = new OleDbCommand(insertSQL);
// Set the Connection to the new OleDbConnection.
command.Connection = connection;
// Open the connection and execute the insert command.
try
{
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// The connection is automatically closed when the
// code exits the using block.
}
}
alright, after this part is clear, off to the next one:
i assume you want to insert to the database only when your page loads right? and not after every button click. so you need to direct asp.net to only execute your code if its a first load and not a postback. you would want to change your page_load function to look like that:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string conn = "";
string sqlCOmmand = "inset blablabla into blablabla";
conn = ConfigurationManager.ConnectionStrings["Conn"].ToString();
InsertRow(conn, sqlCOmmand);
}
}
as for your click handler, you should create another function UpdateRow and do the same with a using() statement and put it in your click handler
Related
I'm hitting a wall right now in my project.
I have a form, with some listboxes, and add button. When I click on the add button, I got a small dialog form with a textbox, an OK and a Cancel button. The app is connected to a MySQL database. So whenever the text change, the program checks if the name exists in the database, disable the OK button and the textbox turn red if the name exists, otherwise it turns them back to normal. Works without a problem when I'm writing and the name doesn't exist, and when it does, it turns red, like it should. And here is the problem. After turning red, it doesn't go back to normal, even when I enter a valid name.
Here is the code :
private void DialogTxb_TextChanged(object sender, EventArgs e)
{
//ConnexionData class where i do all the SQL manipulation
MySqlDataReader selection = ConexionData.CheckSectionName(DialogTxb.Text);
while (selection.Read())
{
if (selection.HasRows)
{
DialogOk.Enabled = false;
toolTip1.Show("La section existe", TooltibLb);
DialogTxb.BackColor = System.Drawing.ColorTranslator.FromHtml("#ffaaaa");
}
else
{
toolTip1.Hide(TooltibLb);
DialogTxb.BackColor = Color.White;
DialogOk.Enabled = true;
}
}
ConexionData.ConexionClose();//Method to close connection
}
I think I have an idea where the problem is but have don't know why it happens and how to solve it. If I simply exit the form and try to do anything else, like select another element from a listbox which will trigger some database interaction, the program close and visual studio provide me with info on the error:"The connexion is already open". I tried to close in other moments of the code, looked for some solutions on the internet, tried MysqlConection.ClearAllPools(), and still the same issue.
Connexion opens and closes properly in other parts of the application.
Thanks for your attention.
Edit
Here are the methods in ConexionData
class ConnexionData
{
private static MySqlConnection Connexion;
public static MySqlCommand Command;
//Many other methods
//.......
public static void ConnexionClose()
{
Connexion.Close();
}
public static MySqlDataReader CheckSectionName(string name)
{
Connexion.Open();
string checkSectionName = ("Select sectionName from section where sectionName = '" + name + "'");
Command.CommandText = checkSectionName;
Reader = Command.ExecuteReader();
return Reader;
}
}
I use the Connexion.Close() in many parts of the program. I have 2 Data Grid views, and some list box where i load data from the database. I open and close those DGV and change values in listbox and all work fine. Then i try my small form to insert a new values on those tables, test it and close it (actually i insert nothing, i simply close it and there is a ConexionData.Close() in the close event) and here where the problem of connection start.
Edit-Solved
I finally solved the problem. I turned Private MysqlConection to public, and directly closed the property after closing the dialog.
if selection.Read() returns true it means you have at least 1 record. It seems you are looking for
private void DialogTxb_TextChanged(object sender, EventArgs e) {
try {
//TODO: check ConexionData.CheckSectionName (re-)creates connection if required
using (MySqlDataReader selection = ConexionData.CheckSectionName(DialogTxb.Text)) {
if (selection.Read()) {
// Name exists (we've read it)
DialogOk.Enabled = false;
toolTip1.Show("La section existe", TooltibLb);
DialogTxb.BackColor = System.Drawing.ColorTranslator.FromHtml("#ffaaaa");
}
else {
// Name doesn't exist: the cursor is empty (so we've failed to read it)
toolTip1.Hide(TooltibLb);
DialogTxb.BackColor = Color.White;
DialogOk.Enabled = true;
}
}
}
finally {
// finally: rain or shine the connection should be closed
ConexionData.ConexionClose(); // Method to close connection
}
}
In case connection is not closing then you can try to call close() connection or sqldatareader before executing method "CheckSectionName()".
FYR Below is some example Let me know, if it helps.
Approch 1:
System.Data.SqlClient.SqlConnection sqlConn = new System.Data.SqlClient.SqlConnection();
if(sqlConn.State!= System.Data.ConnectionState.Closed)
{
sqlConn.Close();
}
System.Data.SqlClient.SqlDataReader SqlReader= new System.Data.SqlClient.SqlDataReader();
if(!SqlReader.IsClosed)
{
SqlReader.Close();
}
MySqlDataReader selection = ConexionData.CheckSectionName(DialogTxb.Text);
Approch 2: We can use "using" clause
using (MySqlDataReader selection = ConexionData.CheckSectionName(DialogTxb.Text))
Approch 3:
Add close() and dispose() into finally block.
Problem from yesterday...still couldn't get sorted.
Have gone through a million post and videos but couldn't find the one that points out what I'm doing wrong. I basically want to retrieve and assign a combobox's value, and send it to an SQL stored procedure's parameter. I was blamed not to provide code enough yesterday so here's a bit more detailed.
SqlConnection _connection;
SqlCommand _command;
_connection = new SqlConnection(#"Data Source=someserver;Initial Catalog=sometable;Integrated Security=True");
_connection.Open();
_command = _connection.CreateCommand();
_command.CommandType = CommandType.StoredProcedure;
private void SelectedIndexChanged(object sender, EventArgs e)
{
try
{
_command.CommandText = "someprocedurename";
_command.Parameters.Add("#someparameter", SqlDbType.NVarChar).Value = combobox1.SelectedItem.ToString();
_command.ExecuteNonQuery();
}
catch (Exception)
{
MessageBox.Show("Error", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_connection.Close();
}
}
What happens: when I select the item in the combobox, it first automatically pops up the error message, then it shows the item in the box, but apparently the value of it is not getting passed to #someparameter, or at least the stored procedure is not getting triggered. The stored procedure, written and tested in SQL, works - the problem is in the C# code. I'm aware this might be a lame question for lots of pros out there, but please considerate I've done my research. Please be as specific as you can - not here to get criticized but to improve my newbie skills. Thanks.
C#, Windows Forms
EDIT:
catch block was amended as Sir Henry recommended.
This is what I see now
and after moving _connection.Open(); into the try block,
this is what I see
Pretty much wtf...
EDIT 2:
it seems the problem is gone, thanks to Sir Henry. All I need to figure out now is how to populate the second combobox, based on the stored procedure that was called by the value of the first combobox. This is how the code looks like now:
private void SelectedIndexChanged(object sender, EventArgs e)
{
using (SqlConnection _connection =
new SqlConnection(#"Data Source=someserver;Initial Catalog=sometable;Integrated Security=True"))
try
{
_connection.Open();
SqlCommand _command = new SqlCommand("someprocedurename", _connection);
_command.CommandType = CommandType.StoredProcedure;
_command.Parameters.Add("#someparameter", SqlDbType.NVarChar).Value = combobox1.SelectedValue.ToString();
_command.ExecuteNonQuery();
/* i guess this is the part where i should "inform" combobox2 about the
result of the stored procedure, based on combobox1. have no idea though,
how it could be done. maybe i need a dataset? clueless. just to be clear:
if value "a" was selected in combobox1, i want to populate combobox2 with
the value "1". if value "b" was selected in combobox1, i want to populate
combobox2 with the value "2". etc. */
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
Have you tried combobox1.SelectedValue.ToString(); instead of combobox1.SelectedItem.ToString();
One of the reasons for this kind of issue is you're binding an entity to the ComboBox. Can you share the code of data binding to the ComboBox?
This should work
SqlConnection _connection;
SqlCommand _command;
_connection = new SqlConnection(#"Data Source=someserver;Initial Catalog=sometable;Integrated Security=True");
_connection.Open();
_command = _connection.CreateCommand();
_command.CommandType = CommandType.StoredProcedure;
private void SelectedIndexChanged(object sender, EventArgs e)
{
try
{
_command.CommandText = "someprocedurename";
_command.Parameters.Add("#someparameter", SqlDbType.NVarChar).Value = combobox1.SelectedValue.ToString();
_command.ExecuteNonQuery();
}
catch (Exception)
{
MessageBox.Show("Error", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_connection.Close();
}
}
I have two functions with the first one filling a comboBox with the tables within my SQL Database, this it below:
private void FillCombo()
{
comboBox1.Items.Clear();
try
{
string connectionString = "Data Source=LPMSW09000012JD\\SQLEXPRESS;Initial Catalog=Pharmacies;Integrated Security=True";
using (SqlConnection con2 = new SqlConnection(connectionString))
{
con2.Open();
string query = "SELECT * FROM INFORMATION_SCHEMA.TABLES ";
SqlCommand cmd2 = new SqlCommand(query, con2);
SqlDataReader dr2 = cmd2.ExecuteReader();
while (dr2.Read())
{
int col = dr2.GetOrdinal("TABLE_NAME");
comboBox1.Items.Add(dr2[col].ToString());
}
comboBox1.SelectedIndex = 0;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
And I have another one which is filling the second comboBox based on the value from the previous function's combobox. This is it below
async void fillLiguanea()
{
comboBox2.Items.Clear();
try
{
string connectionString = "Data Source=LPMSW09000012JD\\SQLEXPRESS;Initial Catalog=Pharmacies;Integrated Security=True";
SqlConnection con = new SqlConnection(connectionString);
con.Open();
string query = "SELECT * FROM " + comboBox1.Text;
SqlCommand cmd = new SqlCommand(query, con);
var reader = await cmd.ExecuteReaderAsync();
comboBox2.BeginUpdate();
while (reader.Read())
{
string scode = reader.GetString(reader.GetOrdinal("code"));
comboBox2.Items.Add(scode);
}
comboBox2.EndUpdate();
comboBox2.SelectedIndex = 0;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}}
What am trying to do is to refresh the "fillLiguanea" function's comboBox value based on the table selected in the "fillCombo" function. Eg. if there are tables with the name "cat" and "dog" in my comboBox that is filled by "fillLiguanea" then when selected it should automatically change the comboBox which is filled by "fillLiguanea" with the various cat or dog breeds.
I was reading and saw something about the SelectionChangeCommitted event. Is this the way to go or is there a better way to do this?
I've achieved this through a refresh button that targets my second comboBox but I would rather eliminate the use of buttons for the user
You have to use events.
See: https://msdn.microsoft.com/en-us/library/awbftdfh.aspx, https://msdn.microsoft.com/en-us/library/edzehd2t(v=vs.110).aspx
In short, an event is simply a way to trigger code by following the Observer Pattern.
Basically, an event represents multiple methods (I'll refer to these as "subscribing methods" as they "subscribe" to the event) that all get called when the event is raised from within the class it is defined in.
"Okay," you might say. "But when implementing a method to be called when the event is raised, how do I ensure I have the correct parameter types?".
Delegates.
A delegate represents the signature of a method (ie, the number of parameters/the parameter types/the method's return type). Each event is declared as being a type of a specific delegate.
For example, let's say you want an event that will call it's subscribing methods when an arbitrary message is received. How would you setup such a system using these things called "Events"?
Define your delegate
public delegate void MessageDelegate(string data);
This means (and enforces) that all subscribing methods to the event must contain just one parameter and it's type must be string. Also that each subscribing method must not return any value.
Define your event
public event MessageDelegate MessageReceived;
This says that we create an event (a collection of subscribed methods) where each subscribing method must match the signature defined by the delegate MessageDelegate.
Subscribe to your event (probably the part you're most interested in)
To subscribe to the event (or add a method to the event's collection of subscribers) you first must create a method that matches the delegate:
private void OnMessageReceived(string msg)
{
//Do something with the received message.
}
Then comes the actual subscribing:
MessageReceived += new MessageDelegate(OnMessageReceived).
Now whenever the event is triggered our OnMessageReceived method will be called.
Finally, to trigger or raise the event (the process of calling each subscribing method) you simply can do:
MessageReceived("Hello World!")
All that being said, how does this apply to your particular problem?
Well, the combobox control already contains the event. So you obviously don't have to define that yourself. That means all you're responsible for is subscribing to the event.
comboBox1.SelectionChangeCommitted += new EventHandler(comboBox1_SelectionChangeCommitted);
private void comboBox1_SelectionChangeCommitted(object sender, EventArgs e)
{
//Refresh combobox 2.
}
I recommend you put the actual subscription in the form's Form_Load event.
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.SelectionChangeCommitted += new EventHandler(comboBox1_SelectionChangeCommitted);
}
Now however, you must subscribe to the form's load event. Typically done in the constructor after the call to InitializeComponent.
public Form1()
{
InitializeComponent();
Load += new EventHandler(Form1_Load);
}
You can of course, bypass the form load subscription
public Form1()
{
InitializeComponent();
comboBox1.SelectionChangeCommitted += new EventHandler(comboBox1_SelectionChangeCommitted);
}
Lastly, if you're using the WindowsForms designer in Visual Studio:
Somewhere on the property pane there should be a way to view events for the selected control. Scroll down to your desired event. Double-click it. Visual studio should automatically create a method and subscribe to the event with the new method.
There is so much power behind events and delegates. I highly encourage you to do some reading up on them.
Sorry this wasn't as small as I envisioned but I thought I would try to explain why it works and not just "This is how it should be done.".
This turned out being a simple solution. I just passed the comboBox from the fillCombo function into the fillLiguanea function and everything worked as I wanted. The two functions are listed below:
This is the fillCombo method which is populating from the SQL database to my comboBox called "comboBox4"
private void FillCombo()
{
comboBox4.Items.Clear();
try
{
string connectionString = "Data Source=LPMSW09000012JD\\SQLEXPRESS;Initial Catalog=Pharmacies;Integrated Security=True";
using (SqlConnection con2 = new SqlConnection(connectionString))
{
con2.Open();
string query = "SELECT * FROM INFORMATION_SCHEMA.TABLES ";
SqlCommand cmd2 = new SqlCommand(query, con2);
SqlDataReader dr2 = cmd2.ExecuteReader();
while (dr2.Read())
{
int col = dr2.GetOrdinal("TABLE_NAME");
comboBox4.Items.Add(dr2[col].ToString());
}
// comboBox4.SelectedIndex = 0;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
And this is my fillLiguanea method that updates the table based on the comboBox4 selection from my above function.
async void fillLiguanea()
{
comboBox2.Items.Clear();
try
{
string connectionString = "Data Source=LPMSW09000012JD\\SQLEXPRESS;Initial Catalog=Pharmacies;Integrated Security=True";
SqlConnection con = new SqlConnection(connectionString);
con.Open();
string query = "SELECT * FROM " + comboBox4.Text;
SqlCommand cmd = new SqlCommand(query, con);
var reader = await cmd.ExecuteReaderAsync();
comboBox2.BeginUpdate();
while (reader.Read())
{
string scode = reader.GetString(reader.GetOrdinal("code"));
comboBox2.Items.Add(scode);
}
comboBox2.EndUpdate();
comboBox2.SelectedIndex = 0;
// comboBox2.Sorted = true;
}
This is the important line of code:
string query = "SELECT * FROM " + comboBox4.Text;
With that everything was solved
Im trying to create UPDATE command to my program based on C# and Access database. And its working how i want it, but VS2013 display error when i try to update another or the same record second time.
InvalidComObjectException was unhandled.
COM object that has been separated from its underlying RCW can not be
used.
This is how my program looks like:
FormA - Main windows with DataGridView1 of table "Grafik" and Button to open FormB
FormB - Second form with DataGridView2 of table Employyes and Button to FormC
FormC - Form to add, delete and update records directly in to the database "Kategorie" using TextBox'es, ComboBox'es and Buttons (no directly on DataGridView)
UPDATE procedure uses ComboBox (comboBoxWybierzKategorie) to select "category" from database "Kategorie" to update, textBox (textBoxEdytujKategorie) to set new name of selected "Kategoria" and Button to accept procedure.
Broker.cs
public void Update_Kategorie(Kategorie oldKategoria, Kategorie newKategoria)
{
try
{
command.CommandText = "UPDATE Kategorie SET Kategoria = #kat WHERE IDKategorii= #old";
//command.CommandType = CommandType.Text;
command.Parameters.AddWithValue("#kat", newKategoria.Kategoria);
command.Parameters.AddWithValue("#old", oldKategoria.IDKategorii);
connection.Open();
//command.ExecuteNonQuery();
int cmd = command.ExecuteNonQuery();
//connection.Close();
if (cmd > 0)
{
MessageBox.Show("Kategoria zaktualizowana pomyślnie");
//connection.Close();
}
else
{
MessageBox.Show("Wystąpił błąd podczas aktualizacji kategorii.",
"Dodawanie kategorii",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
}
}
catch (OleDbException ex)
{
FormC.cs
private void buttonEdytujKategorie_Click(object sender, EventArgs e)
{
Kategorie oldKategoria = new Kategorie();
Kategorie newKategoria = new Kategorie();
oldKategoria = comboBoxWybierzKategorie.SelectedItem as Kategorie;
newKategoria.Kategoria = Convert.ToString(textBoxEdytujKategorie.Text);
b.Update_Kategorie(oldKategoria, newKategoria);
comboBoxWybierzKategorie.DataSource = b.FillComboBox_Kategorie(); //wypełnij comboBoxWybierzKategorie
textBoxEdytujKategorie.Text = String.Empty; //wyczyść textBoxEdytujKategorie
//this.Close();
//this.Controls.Clear();
//this.InitializeComponent();
I know that code is messed up, sorry for that. More interesting is when i close FormC and reopen it using Button, update function working fine, unless i want use it again.
VS2013 selecting this line as a reason of error:
int cmd = command.ExecuteNonQuery();
Connection to database:
OleDbConnection connection;
OleDbCommand command;
private void ConnectTo()
{
//inside//connection = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=bc3e-ps.accdb");
/*outside*/
connection = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\bc3e-ps.accdb");
command = connection.CreateCommand();
What im doing wrong?
Since you are adding parameters to the command every time, you should not re-use the command object again.
Just call connection.CreateCommand() every time you want to execute another command.
You can re-use commands, but then you only want to set the existing parameters on each call instead of adding parameters on each call.
I'm trying to make a DataGridView that displays data from an SQL database (GSM.sdf) and saves changes made to the DataGridView back to the database when a save button is pressed. The data displays fine, but nothing happens when the save button is pressed. I've been following the top answer from this thread:
http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/98bc0b4d-a2ea-4b74-81f0-473da624528a
But it isn't working out. Here is my code:
namespace WindowsFormsApplication5
{
public partial class Zeelot : Form
{
DataTable table = new DataTable();
SqlCeDataAdapter z;
DataSet gSMDataSet = new DataSet();
public Zeelot()
{
InitializeComponent();
}
private void Zeelot_Load(object sender, EventArgs e)
{
string b = #"Data Source =.\SQLEXPRESS;database=GSM;Integrated Security=FALSE;Connection Timeout=30;User Instance=FALSE";
SqlCeConnection conn = new SqlCeConnection(b);
conn.Open();
string cd = "SELECT * FROM PhoneNumbers";
z = new SqlCeDataAdapter(cd, conn);
z.Fill(gSMDataSet, "PhoneNumbers");
table = gSMDataSet.Tables[0];
conn.Close();
dataGridView1.DataSource = table;
}
private void SaveButton_Click(object sender, EventArgs e)
{
SqlCeCommandBuilder local_SqlCommandBuilder = new SqlCeCommandBuilder(z);
local_SqlCommandBuilder.ConflictOption = System.Data.ConflictOption.OverwriteChanges;
z.UpdateCommand = local_SqlCommandBuilder.GetUpdateCommand();
z.Update(((System.Data.DataTable)this.dataGridView1.DataSource));
((System.Data.DataTable)this.dataGridView1.DataSource).AcceptChanges();
}
}
}
I believe your problem lies where you are casting a DataSource to System.Data.DataTable
Try z.Update(gSMDataSet);
I also don't believe you need AcceptChanges()
you dont need to call .AcceptChanges() on the DataGridView at the end.
AcceptChanges() submits the changes from your DGV to the connected DataSource (your DataTable)
Try calling AcceptChanges() before you try to submit the changes to your Database.
I think your problem is with your connection. You manually create and open a connection and assign it to your DataAdapter. But within your _Load() Method, you close the connection. As the DataAdapter used inside the _Click EventHandler is the same as the one used in your _Load() Method (therefore uses the same connection). It can't submit any changes to your Database because you already closed the connection.
Don't you get any exceptions at runtime?
Try using breakpoints to examine the current state of your connection Object before you attempt to submit your changes to your Database.
Also, AFAIK MS advises against creating connections manually if you want to use them within a DataAdapter.
DataAdapter's Constructor can create a connection on its own