Why doesn't my SQLite database table update? (datatable update) - c#

I have a c# application with an SQLite database. It has a table called "Results_to_Risks" which I am trying to update. I first remove some rows in my local datatable, after which I use my update table function to update the table in the database.
foreach(var row in temp)
{
allResToRisks.Rows.Remove(row);
}
_databaseController.UpdateTable(allResToRisks, "Results_to_Risks");
My database controller update table method:
// Updates an entire database table.
public void UpdateTable(DataTable datatable, string table, string condition = "")
{
using (SQLiteConnection dbConnection = new SQLiteConnection(conString))
{
using (var sqliteAdapter = new SQLiteDataAdapter("SELECT * FROM '" + #table + "'" + #condition, dbConnection))
{
dbConnection.Open();
using(var builder = new SQLiteCommandBuilder(sqliteAdapter))
{
sqliteAdapter.Update(datatable);
}
}
}
}
In this particular case, I remove just one row. The datatable ends up empty (Rows.Count == 0), because this was the only row in that datatable. So nothing goes wrong there. However my table in the database still has the one row inside it.
What am I doing wrong?
I saw this on the MDSN website:
It is important to understand the difference between deleting a row in a DataTable and removing the row. When you call the Remove or RemoveAt method, the row is removed immediately. Any corresponding rows in the back end data source will not be affected if you then pass the DataTable or DataSet to a DataAdapter and call Update. When you use the Delete method, the row remains in the DataTable and is marked for deletion. If you then pass the DataTable or DataSet to a DataAdapter and call Update, the corresponding row in the back end data source is deleted.
So i tried to use Delete() instead of Remove(). However, this made no difference.

Related

Get Inserted Row after .Net Dataset Row Added

I have a .Net dataset and am adding a row to a table. This works and the record is saved to the database. How do I get the updated version of my row after the insert. Or, alternatively, how do I know the ID of the item that was added (so that I can then use it in a subsequent child table insert.
MyDataSet.ProjectRow r = dsMyDataSet.Projects.AddProjectRow(txtTitle.Text);
m_daProjects.Update(dsMyDataSet.Projects);
// What is the ID of the new item here?
If the column is an identity column you can find the new ID's in the inserted rows.
You: "thanks. which object maintains a list of inserted rows?"
You can use DataTable.GetChanges(DataRowState.Added) to get a DataTable with all DataRows which are going to be added. You need to use it before AcceptChanges was called. If i remember correctly TableAdapter.Update calls AcceptChanges at the end. Then you need to use it before m_daProjects.Update(dsMyDataSet.Projects):
DataTable addedRows = ds.modModel.GetChanges(DataRowState.Added);
MyDataSet.ProjectRow r = dsMyDataSet.Projects.AddProjectRow(txtTitle.Text);
m_daProjects.Update(dsMyDataSet.Projects);
now addedRows contains all DataRows with the new identity value in each row
foreach(DataRow addedRow in addedRows.Rows)
Console.WriteLine("New ID: {0}", addedRow.Field<int>("IdColumn"));
Update: However, in your case it's simpler. You have already the single row that you want to insert. So you dont need to call DataTable.GetChanges at all.
You can see the new identity value in the (typed DataRow) ProjectRow r after Update.
Thanks to Tim Schmelter. In the link he posted there's a reference to an article on Beth Massi's blog with a complete walkthrough of the solution. It worked for me.
http://blogs.msdn.com/bethmassi/archive/2009/05/14/using-tableadapters-to-insert-related-data-into-an-ms-access-database.aspx
The basic steps are:
1) Add RowUpdated event handler on the strongly typed table adapter. This event handler issues a new OleDBCommand to the database to retrieve ##Identity and then assigns the integer to the member column of the table.
public void _adapter_RowUpdated(dynamic sender, System.Data.OleDb.OleDbRowUpdatedEventArgs e)
{
HMUI.Classes.AccessIDHelper.SetPrimaryKey(this.Connection, e);
}
public static void SetPrimaryKey(OleDbConnection trans, OleDbRowUpdatedEventArgs e)
{
if (e.Status == System.Data.UpdateStatus.Continue && e.StatementType == System.Data.StatementType.Insert)
{
if (pk != null)
{
OleDbCommand cmdGetIdentity = new OleDbCommand("SELECT ##IDENTITY", trans);
// Execute the post-update query to fetch new ##Identity
e.Row.Table.Columns[pk(0)] = Convert.ToInt32(cmdGetIdentity.ExecuteScalar());
e.Row.AcceptChanges();
}
}
}
2) In the constructor of the form using the dataset and table adapter I attach the function in step 1 to the RowUpdated event on the table adapter's internal data adapter.
// Event to handle inserted records and retrieve the primary key ID
m_daDataSources.Adapter.RowUpdated += new System.Data.OleDb.OleDbRowUpdatedEventHandler(m_daDataSources._adapter_RowUpdated);

The RemoveAt method seems to remove the desired value but the update is not being made in the database

I want to retrieve the data from a table in the database into a Datatable and I would like to delete a few rows from the Datatable based on the values and update the changes made to the Datatable in the database.
I have been using the below code for deleting.
DataTable dt_table = new DataTable();
SqlConnection conn=new SqlConnection(connectionStr);
SqlCommand cmd = new SqlCommand("SELECT * FROM RT_Table", conn);
SqlDataAdapter sqlda = new SqlDataAdapter(cmd);
conn.Open();
sqlda.Fill(dt_table);
for (int i = 0; i < dt_table.Rows.Count; i++)
{
if (dt_table.Rows[i]["Name"].ToString()=="TEST")
{
dt_table.Rows.RemoveAt(i);
}
}
sqlda.Update(dt_table);
The RemoveAt method seems to remove the desired value but the update is not being made in the database.
I have been able to perform the INSERT into the Datatable and was able to update the table in the Database. For insert I used InsertCommand.
First, you should create an SqlCommandBuilder that provides the DeleteCommand required by the adapter to execute the delete, then you should use the Delete() method on the row, not RemoveAt().
The two methods have different meaning and purposes
SqlCommandBuilder builder = new SqlCommandBuilder(sqlda);
foreach(DataRow row in dt_table.Rows)
{
if (row["Name"].ToString()=="TEST")
{
row.Delete();
}
}
sqlda.Update(dt_table);
Delete() marks the row with the DataRowState.Deleted flag and then when you call Update() the DeleteCommand of the DataAdapter should be able to retrieve the rows marked with that flag and remove them from the database table. Instead the method RemoveAt(i) marks the row with the mentioned flag, but immediately calls AcceptChanges(). This method removes the row with DataRowState.Deleted from the in memory Rows collection. Thus, when you call the Update() method there is no row with the DataRowState.Deleted and the DeleteCommand is not executed.

DataRow.AcceptChanges won't keep the new RowState

This test code is really straightforward
var addedRows1 = (securityDataTable.GetChanges(DataRowState.Added));
MessageBox.Show(addedRows1.Rows[1].RowState.ToString());
MessageBox.Show(addedRows1.Rows.Count.ToString());
addedRows1.Rows[1].AcceptChanges();
var addedRows2 = (securityDataTable.GetChanges(DataRowState.Added));
MessageBox.Show(addedRows2.Rows[1].RowState.ToString());
MessageBox.Show(addedRows2.Rows.Count.ToString());
The 4 MessageBox show, in order, the following messages:
Added
3
Added
3
I would expect the count to return 2 on the last message. Why isn't that the case and can this be fixed by any mean? Note: The DataTable is not linked to a table nor a particular data source.
EDIT: Note that the RowState is ok (set to Unchanged) if I don't requery the GetChanges() the second time
GetChanges returns a copy of the rows. Are you using a data adapter to fill your data table? MSDN recommends calling AcceptChanges on the DataAdapter'
private void UpdateDataTable(DataTable table,
OleDbDataAdapter myDataAdapter)
{
DataTable xDataTable = table.GetChanges();
// Check the DataTable for errors.
if (xDataTable.HasErrors)
{
// Insert code to resolve errors.
}
// After fixing errors, update the database with the DataAdapter
myDataAdapter.Update(xDataTable);
}
Edit
Since you are just using a datatable, you could create a query for the rows that are added and call AcceptChanges on that row:
DataRow[] addedRows = datatable.Select(null, null, DataViewRowState.Added);
foreach (DataRow _ddr in addedRows)
{
_ddr.AcceptChanges();
}

How to replace a DataBase Table by a DataTable

I am trying to replace a Table (FooTable) in my DataSource (an SQL CE Database) by a DataTable (which bind to a DataGrid). The reason I want to do this is: after I populate from a Database to a DataSet (which show all the rows on the DataGrid), I might edit, delete, and add multiple rows to the DataTable. Instead of updating my changes to DataSource (SQL CE) each time I modified the DataTable, I want to do it collectively at the end of the session.
My approach is straight-forward:
`DELETE` all data from my DataSource table (FooTable) (I'm using **SQL CE**, so `TRUNCATE` is not available)
INSERT the `DataTable's` data in to the emptied DataSource Table
Following is my C# code
/* Truncate the DataSource Table */
SqlCeCommand delCmd = new SqlCeCommand("DELETE FROM FooTable", conn)
conn.Open();
delCmd.ExecuteNonQuery();
conn.Close();
/* Insert DataTable into an empty DataSource Table */
string ins = #"INSERT INTO FooTable (FooName) values (#fooName)";
SqlCeCommand cmd = new SqlCeCommand(ins, conn);
da.InsertCommand = cmd;
da.Update(ds, "FooTable");
The codes work if I add or delete rows on the DataTable, but when I edit a specific row on the DataTable and Insert the table to my DataSource, I get the following error
"Update requires a valid UpdateCommand when passed DataRow collection with modified rows."
I do not understand why I get this error. I have already empty all rows in my DataSource table and my DataSource shouldn't not know there are modified rows but insert all DataTable Rows as new rows.
Or, is there a simple way to "REPLACE" a DataSource table by a DataTable?
[EDITED]
I tried setting the RowState manually like below code
foreach (DataRow row in dt.Rows)
{
row.RowState = DataRowState.Added;
}
but RowState is only read only and cannot be written.
[EDITED - 2nd]
I tried setting it using SetAdded()
foreach (DataRow row in dt.Rows)
{
row.SetAdded();
}
Then I get the following error:
"SetAdded and SetModified can only be called on DataRows with Unchanged DataRowState."
Still not manage to get it to work...
[EDITED - 3rd]
So finally get it to work with the following code:
using (SqlCeCommand insCmd = new SqlCeCommand(#"INSERT INTO FooTable (FooName) VALUES (#fooName)", conn))
{
insCmd.Parameters.Add("#fooName", SqlDbType.NVarChar, 10, "FooName");
dt.AcceptChanges();
foreach (DataRow row in dt.Rows)
{
row.SetAdded();
}
da.InsertCommand = insCmd;
da.Update(ds, "FooTable");
}
The DataTable tracks RowStates internally.
When you modify an existing row, its RowState becomes Modified, so the DataAdapter tries to run an UPDATE command.
You need to call the SetAdded() method on the modified rows to set their RowStates to Added rather than Modified.

Inserting just a new record using DataSet (.net c# ado.net )

I've a form containing more than 200 text boxes in .NET desktop application. I want to insert them into their respective 4 tables of Database. Now how should I go about it using Dataset & DataAdapter to do this?
I mean usually this will be the flow:
Populate the DataSet using DataAdapter.Fill(Dataset,"DataTable");
manipuate the data of DataSet
DataAdapter.Update(Dataset,"DataTable") updates the content back to Database.
Code:http://dev.mysql.com/doc/refman/5.1/en/connector-net-tutorials-intro.html#connector-net-tutorials-data-adapter
But here I just want to insert a new record in 3 different tables.
I think the way is to
Programmatically Create A dataset with 3 Datatables.
Bind 200 Textboxes to respective columns of these Datatabes
dataAdapter.Update(dataSet, dataTable.TableName);
Am I right?
How does dataAdapter.Update(dataSet, dataTable.TableName); work? Because, my each dataTable will have only one record. (the new record that is to be inserted. binded with those 200 TextBoxes of the form) where as the Table of the Database will have thousands of records. If I do dataAdapter.Update(dataSet, dataTable.TableName); will it delete all the rest of the records and insert this one alone?
I just want to insert a new record (without fetching other 1000s of records into my Dataset) into Database.Table using Dataset.
Each row has a RowState Property, this will be used by the dataAdapter. So if your dataset has only one new row, the row state will be DataRowState.Added. The DataAdapter will insert the row and change the row state to DataRowState.Unchanged. All other rows in the database will be unchanged.
IDbTransaction dbTransaction = dbConnection.BeginTransaction();
try
{
foreach (DataTable dataTable in dataSet.Tables)
{
string sql = "SELECT * FROM " + dataTable.TableName + " WHERE 0 = 1";
SqlDataAdapter dataAdapter = new SqlDataAdapter (sql, dbConnection);
dataAdapter.Update(dataSet, dataTable.TableName);
}
}
catch
{
dbTransaction.Rollback();
throw;
}
dbTransaction.Commit();
Remark: Will not work if there are constraints in the database defined.
Simply make the SQL insert commands and execute them:
string cmd="insert into myTable(column1, column2, etc) values (#text1,#text2, etc)";
SqlCommand sqlcmd=new SqlCommand(cmd,mySqlConnection);
sqlcmd.Parameters.Add("#text1",SqlDbType.NChar,textbox1.Text);
sqlcmd.Parameters.Add("#text2",SqlDbType.NChar,textbox2.Text);
sqlcmd.ExecuteNonQuery();

Categories