It's been a while since I've tried programming something. I've been practicing basic CRUD on a DGV and database. I've got my "ADD/CREATE" function working, but my delete doesn't seem to work.
here's a screenshot:
EDIT:
Posting code here; this is my working ADD/CREATE function:
private void btnAdd_Click(object sender, EventArgs e)
{
connectionstring = "server=" + server + ";" + "database=" + database +
";" + "uid=" + uid + ";" + "password=" + password + ";";
con = new MySqlConnection(connectionstring);
con.Open();
MySqlDataAdapter da = new MySqlDataAdapter("select * from testdatabase", con);
DataSet ds = new DataSet();
da.Fill(ds);
testTable1.DataSource = ds.Tables[0];
con.Close();
// now instead of these next 4 lines
DataRow row = ds.Tables[0].NewRow();
row[0] = tbID.Text;
row[1] = tbName.Text;
ds.Tables[0].Rows.Add(row);
// ds.Tables[0].Rows.RemoveAt(testTable1.CurrentCell.RowIndex);
// is what i used to delete
// what did i do wrong?
MySqlCommandBuilder cb = new MySqlCommandBuilder(da);
da.UpdateCommand = cb.GetUpdateCommand();
da.Update(ds);
((DataTable)testTable1.DataSource).AcceptChanges();
}
If you want to remove a row following a button click you could follow this pseudocode.
First you check if there is a current row selected in the grid,
If you found one then get the value from the cell where the primary
key for the database table is stored. (Here I assume that this cell
is the first one in the row and refers to the column ID in the
database table)
With that data open the connection, prepare the DELETE command with
parameters and call ExecuteNonQuery to phisycally remove the row from
the database table.
After that you could remove the current row from the grid and inform
the underlying datasource that the operation is
complete.(AcceptChanges)
private void btnDelete_Click(object sender, EventArgs e)
{
// No row to delete?
if(testTable1.CurrentRow == null)
return;
// Get the cell value with the primary key
int id = Convert.ToInt32(testTable1.CurrentRow.Cells[0].Value)
// Start the database work...
connectionstring = .....;
using(con = new MySqlConnection(connectionstring))
using(cmd = new MySqlCommand("DELETE FROM testdatabase where id = #id", con))
{
con.Open();
cmd.Parameters.AddWithValue("#id", id);
cmd.ExecuteNonQuery();
// Fix the grid removing the current row
testTable1.Rows.Remove(testTable1.CurrentRow);
// Fix the underlying datasource
((DataTable)testTable1.DataSource).AcceptChanges();
}
}
Related
I use the following code to fill a DataGridView from an Access Database. After a Save button is clicked if the Data Grid is updated, the Database saves the data.
The strange thing is that this works for 2 out of 3 Data Tables. For the last one it throws an exception:
Syntax error in INSERT INTO statement
public Tables(string tabName)
{
InitializeComponent();
this.Text = tabName;
this.query = string.Format("SELECT *" + " FROM [{0}]", tabName);
conn.Open();
detailTable = new DataTable();
string tableName = tabName;
string query = string.Format("SELECT * FROM [{0}]", tableName);
OleDbDataAdapter detailAdapter = new OleDbDataAdapter(query, conn);
if (detailAdapter != null)
{
detailAdapter.Fill(detailTable);
}
DataGridView.DataSource = detailTable;
conn.Close();
}
private void BtnSave_Click(object sender, EventArgs e)
{
OleDbCommand comm = new OleDbCommand(query, conn);
OleDbDataAdapter adapter = new OleDbDataAdapter(comm);
OleDbCommandBuilder builder = new OleDbCommandBuilder(adapter);
adapter.Update(detailTable);
}
Even if the words are reserved keywords (although I searched them) there is no way of that to be the issue.
More information the tabName can be "Partners", "Salaries", "Descriptions" and "Accounts". It doesn't work only on "Partners".
Okay, turns out I was wrong and I apologize for my stubbornness. The problem was in the e-mail column and I did not see why it had a problem with the dash mark.
So I have this DataGridView on which there are two columns which I am retrieving from my SQL Server database. Now, in the second column, we have a bit field which shows as a CheckBox in my Windows Application designer. So, I want to, on CellContentClick event be able to update the value that just got deselected into my database. But seems like I am going nowhere.
Here is my code below:
private void gvTurnOffNotifications_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
foreach (DataGridViewRow row in gvTurnOffNotifications.Rows)
{
DataGridViewCheckBoxCell cell = row.Cells[1] as DataGridViewCheckBoxCell;
//We don't want a null exception!
if (cell.Value != null)
{
bool result = Convert.ToBoolean(row.Cells[1].Value);
if (result == true)
{
//It's checked!
btnUpdateTurnOff.Enabled = true;
myConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
int temp = 1;
bool change = false;
string procedureName = "update UsersNotified Set AllowNotification='" + change + "' where AllowNotification='" + false+ "'";
mySQLCommand = new SqlCommand(procedureName, mySQLConnection);
mySQLCommand.CommandType = CommandType.Text;
mySQLCommand.Connection = mySQLConnection;
mySQLCommand.Connection.Open();
mySQLCommand.ExecuteNonQuery();
}
}
}
}
}
And then when I click on my "Update" button, I want to send the updated griddata for storing in my database as below:
private void btnUpdateTurnOff_Click(object sender, EventArgs e)
{
myConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
mySQLDataAdapter = new SqlDataAdapter("spGetAllUpdatedNotifications", mySQLConnection);
mySQLDataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
mySQLCommand.Connection = mySQLConnection;
mySQLCommand.Connection.Open();
DataSet ds = new DataSet();
mySQLDataAdapter.Fill(ds);
mySQLDataAdapter.UpdateCommand = mySQLCommand;
mySQLDataAdapter.Update(ds);
}
}
The spGetAllUpdatedNotifications object in my Update block is a stored procedure I am calling just to retrieve the records from the database so I can update them on the fly in my DataSet. Here is the definition below:
create proc spGetAllUpdatedNotifications
as
begin
SELECT UserName, AllowNotification FROM UsersNotified where AllowNotification=1
end
GO
For more context: When my form loads, I am selecting all the records from the database which have their AllowNotification field set to bit 1 (true in C#) and once a user unticks a specific user (in other words, that user would not be allowed to receive notifications anymore) and once I click on the Update button, it should set the property to false (bit 0 in the database).
Instead of updating the one record which I have deselected, it updates all of them. "All" in this case are the records which have AllowNotification=1. I only want to set AllowNotification=0 for the deselected/unchecked record only
Any suggestions on how I can go about achieving this?
I am not sure what logic makes you to loop thru all the rows of the DataGridView just to update one row in the database.
If you want to update AllowNotification value for the username for which checkbox is checked or unchecked the logic would be this.
Figure out the updated value of the checkbox which is clicked in the gridview.
Store the updated value (True or False) in a boolean variable.
Retrieve the corresponding username of from the other cell of the same row the gridview.
Execute update query with criteria "WHERE UserName = {userName}".
You need to write CellContentClick event of the DataGridView as following.
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 1) //Assuming Checkbox is displayed in 2nd column.
{
this.dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
var result = this.dataGridView1[e.ColumnIndex, e.RowIndex].Value;
var userName = this.dataGridView1[0, e.RowIndex].Value; //Assumin username is displayed in fist column
var connectionString = "Your Connection String";
//Set value of your own connection string above.
var sqlQuery = "UPDATE UsersNotified SET AllowNotification = #allowNotification WHERE UserName = #userName";
using (var connection = new SqlConnection(connectionString))
{
using (var command = new SqlCommand(sqlQuery, connection))
{
command.CommandType = CommandType.Text;
command.Parameters.Add("#allowNotification", SqlDbType.Bit).Value = result;
command.Parameters.Add("#UserName", SqlDbType.NVarChar).Value = userName;
connection.Open();
command.ExecuteNonQuery();
}
}
}
}
This should help you resolve your issue.
I have a partial solution (It doesn't work a 100% but at least its a step in the right direction):
private void gvTurnOffNotifications_SelectionChanged(object sender, EventArgs e)
{
if (gvTurnOffNotifications.SelectedCells.Count > 0)
{
int selectedrowindex = gvTurnOffNotifications.SelectedCells[0].RowIndex;
DataGridViewRow selectedRow = gvTurnOffNotifications.Rows[selectedrowindex];
getUserSelected = Convert.ToString(selectedRow.Cells["UserName"].Value);
MessageBox.Show(getUserSelected);
foreach (DataGridViewRow row in gvTurnOffNotifications.Rows)
{
DataGridViewCheckBoxCell cell = row.Cells[1] as DataGridViewCheckBoxCell;
//We don't want a null exception!
if (cell.Value != null)
{
//It's checked!
btnUpdateTurnOff.Enabled = true;
myConnectionString = ConfigurationManager.ConnectionStrings["FSK_ServiceMonitor_Users_Management.Properties.Settings.FSK_ServiceMonitorConnectionString"].ConnectionString;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
bool change = false;
string procedureName = "update UsersNotified Set AllowNotification='" + change + "' where UserName='" + getUserSelected + "'";
//MessageBox.Show(cell.Value.ToString());
mySQLCommand = new SqlCommand(procedureName, mySQLConnection);
mySQLCommand.CommandType = CommandType.Text;
mySQLCommand.Connection = mySQLConnection;
mySQLCommand.Connection.Open();
mySQLCommand.ExecuteNonQuery();
}
}
}
}
}
Problem is that it just takes the first row without me having selected the row I want to deselect.
My task should be quite simple but after hours and hours I must admit I'm completely stuck!
I simply want to delete a datarow from a datatable. My datatable is a copy of the table in my current dataset in a SQLite databank. It is mandatory to use the table.row.Delete() method. I am aware that delete() just marks the row to be deleted upon table update.
Below is the code I'm currently using:
I retrieve my data via:
public DataTable GetTable(string tableName)
{
string connectionPath = dbVariables.ConnectionString;
try
{
SQLiteConnection myConnection = new SQLiteConnection(connectionPath);
myConnection.Open();
string cmdStr = "SELECT * FROM " + tableName;
DataTable myTable = new DataTable();
SQLiteDataAdapter myAdapter = new SQLiteDataAdapter(cmdStr, myConnection);
myAdapter.FillSchema(myTable, SchemaType.Source);
myTable.Columns[dbVariables.ClassesID].AutoIncrement = true;
myTable.Columns[dbVariables.ClassesID].AutoIncrementSeed = 1;
myTable.Columns[dbVariables.ClassesID].AutoIncrementStep = 1;
myAdapter.Fill(myTable);
myConnection.Close();
return myTable;
}
catch (SQLiteException e)
{
MessageBox.Show(e.ToString());
return null;
}
}
Here I manipulate my data:
if (myResult == DialogResult.Yes)
{
//killTable.AcceptChanges();
DataRow[] dr = killTable.Select("" + cmVariables.ClassName + " = '" + cmbClasses.Text + "'");
//First I need to evaluate the row index of the row I want to delete
string indexName = (killTable.Rows.IndexOf(dr[0])).ToString();
int i = Int32.Parse(indexName);
// And we are done - I got my row index
DataRow modifiedRow = killTable.Rows[i];
killTable.Rows[i].Delete();
//I inserted this messagebox just to see the rowstatus - and yes, it is marked as deleted on runtime...
MessageBox.Show(killTable.Rows[i].RowState);
// I refer to this in the text below
killTable.AcceptChanges();
killClass_Execution(killTable, cmbClasses.Text, ShortClassNm);
}
And at least the code to update my datatable back to the databank:
public void UpdateTable(string tableName, DataTable sourceTable, bool newOrEdit)
{
try
{
string connectionPath = dbVariables.ConnectionString;
//Connection erstellen --> der connectString gibt dabei den Pfad an.
SQLiteConnection myConnection = new SQLiteConnection(connectionPath);
myConnection.Open();
//Einen Befehls-String erstellen, der das UPDATE-Command auslöst
// UPDATE cm_ClassTest SET className = userEditInput WHERE className = 'oldClassName'
string myUpdateString = "SELECT * FROM " + tableName + "";
SQLiteDataAdapter myAdapter = new SQLiteDataAdapter(myUpdateString, myConnection);
SQLiteCommandBuilder comBuild = new SQLiteCommandBuilder(myAdapter);
myAdapter.DeleteCommand = comBuild.GetDeleteCommand(true);
myAdapter.UpdateCommand = comBuild.GetUpdateCommand(true);
myAdapter.InsertCommand = comBuild.GetInsertCommand(true);
myAdapter.Update(sourceTable);
myConnection.Close();
if (newOrEdit == true)
{
MessageBox.Show("Klasse erstellt!");
}
else
{
MessageBox.Show("Klasse aktualisiert!");
}
}
catch (SQLiteException e)
{
MessageBox.Show(e.ToString());
}
}
In the code block for manipulating data you will find the AcceptChanges() method. At this time, there may have been no other changes appeared to my datatable - so after app start, deleting a row may be the users first action.
Also: each entry in my dataset is unique (school classes that are labeled with a unique class name).
Any help will be highly appreciated!
Regards,
Aran
OK - so I succeeded (finally). Debugging showed no issues, except for AcceptChanges() which got a call but did not result in actually deleting the dataRow.
All I can think of right now is that my primary approach to it was part of the problem: I get my DataTable right from the DataBase, do all the manipulations with it, and then send it back to DB via Update (see my update method above). The SQLite CommandBuilder seems not capable of interpreting my DAtaRow which is by then flagged 'Deleted', but kind of rubber-stamps it to the end of the method without throwing an exception.
By doing so I tried the GetChanges-Method:
DataRow[] dr = killTable.Select("" + cmVariables.ClassName + " = '" + cmbClasses.Text + "'");
string indexName = (killTable.Rows.IndexOf(dr[0])).ToString();
int i = Int32.Parse(indexName);
killTable.Rows[i].Delete();
DataTable killItTable = killTable.GetChanges(DataRowState.Deleted);
killClass_Execution(killItTable, cmbClasses.Text, ShortClassNm);
Now it's working - the copy of killTable (killItTable - stupid I know, but first thing I do tomorrow morning is give it better names :) ) provides info for the sql commandbuilder which seems to be recognized by it.
Whatever it is - it now works.
I think this is not supposed to happen - if someone can come up with any good suggestions, on how to improve my approach, I shall be glad.
best regards
This is my code:
private void CostList_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'lSEStockDataSet.CostPrice' table. You can move, or remove it, as needed.
this.costPriceTableAdapter.Fill(this.lSEStockDataSet.CostPrice);
con = new System.Data.SqlClient.SqlConnection();
con.ConnectionString = "Data Source=tcp:SHEN-PC,49172\\SQLEXPRESS;Initial Catalog=LSEStock;Integrated Security=True";
con.Open();
DataGridView datagridview1 = new DataGridView();
String retrieveData = "SELECT CostID, SupplierName, CostPrice FROM CostPrice WHERE PartsID ='" + textBox1.Text + "'";
SqlCommand cmd = new SqlCommand(retrieveData, con);
int count = cmd.ExecuteNonQuery();
SqlDataReader dr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
dataGridView1.DataSource = dt;
con.Close();
}
private void button1_Click(object sender, EventArgs e)
{
if (dataGridView1.Rows.Count > 0)
{
int nRowIndex = dataGridView1.Rows.Count-1;
if (dataGridView1.Rows[nRowIndex].Cells[2].Value != null)
{
textBox2.Text = Convert.ToString(dataGridView1.Rows[nRowIndex].Cells[2].Value);
}
else
{
MessageBox.Show("NULL");
}
}
}
It shows NULL when i clikc the button, what is the problem here? I have 3 columns there, i want to get the data of the 3rd column of the last row, but it shows NULL but there is data in the specified cell. Anyone knows how to solve this problem?
Instead of subtracting one from the row count, try subtracting two. Subtracting one is giving you the zero-based index of the "add" row, which indeed has a null value in the last column.
int nRowIndex = dataGridView1.Rows.Count-2;
By subtracting 2 from the count, you will get the zero-based index of the last row with actual data in it. I think this is what you are looking for.
As an aside, you will likely want to parameterize your SQL query, something like this:
String retrieveData = "SELECT CostID, SupplierName, CostPrice FROM CostPrice WHERE PartsID = #inPartsID";
SqlCommand cmd = new SqlCommand(retrieveData, con);
cmd.Parameters.Add(new SqlParameter("#inPartsID", textBox1.Text));
This will make your query more reliable (what happens if there is a single quote character in textBox1) and your data more secure (evil-doers can use SQL injection to cause harm to your database or get data out of it that they shouldn't).
I've tried various solutions I have found and either I don't know how to implement them properly or they simply won't work. I have a method that allows someone to search a table for a specific order number, then the rest of the row will display in a gridview. However, if an order number is entered that doesn't exist in the table then I can get server error/exception. How can I make it so that before the search goes through or while the search goes through, if an order number that does't exist in the database is searched for then I can create the error instead?
I am using an ms access database, C#, and ASP.
Here is some of the code I am working with:
the method for searching the order table:
public static dsOrder SearchOrder(string database, string orderNum)
{
dsOrder DS;
OleDbConnection sqlConn;
OleDbDataAdapter sqlDA;
sqlConn = new OleDbConnection("PROVIDER=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + database);
DS = new dsOrder();
sqlDA = new OleDbDataAdapter("select * from [Order] where order_num='" + orderNum + "'" , sqlConn);
sqlDA.Fill(DS.Order);
return DS;
}
And using that method:
protected void btnSearch_Click(object sender, EventArgs e)
{
Session["OrderNum"] = txtSearch.Text;
Session["ddl"] = ddlSearch.Text;
if (Session["ddl"].ToString() == "Order")
{
dsOrder dataSet2;
dataSet2 = Operations.SearchOrder(Server.MapPath("wsc_database.accdb"), Session["OrderNum"].ToString());
grdSearch.DataSource = dataSet2.Tables["Order"];
grdSearch.DataBind();
}
Do I need to do a try/catch?
A huge thanks in advance to who is able to help me!
You can simply do a check to see whether DataSet is empty
if (dataSet2 == null || dataSet2.Tables.Count == 0 || dataSet2.Tables["Order"] == null || dataSet2.Tables["Order"].Rows.Count == 0)
{
//display error to user
}
else
{
// your code to populate grid
}
If you don't want to show error then just put this check before populating GridView
if (dataSet2.Tables != null && dataSet2.Tables["Order"] != null)
{
// your code to populate grid
}
I use a different approach when filling data grids and always use parameters as follows:
public static DataTable GetGridDatasource(string database, string ordnum) {
using (OleDbConnection con = new OleDbConnection("PROVIDER=Microsoft.ACE.OLEDB.12.0;Data Source=" + database))
{
con.Open();
OleDbCommand cmd = con.CreateCommand();
cmd.CommandText = "select * from [Order] where order_num=[OrderNumber]";
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("OrderNumber", ordnum);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
protected void btnSearch_Click(object sender, EventArgs e)
{
Session["OrderNum"] = txtSearch.Text;
Session["ddl"] = ddlSearch.Text;
if (Session["ddl"].ToString() == "Order")
{
grdSearch.DataSource = GetGridDatasource(Server.MapPath("wsc_database.accdb"), Session["OrderNum"].ToString());
}
}