I wrote a simple test to check my dataAdapter code. I connect to the SQL Server database, fill a datatable, change a value in a row, and call da.Update(table) to send the changes back to SQL Server. The table has a primary key. Not at all sure why this isn't working...(see code)
connectionToSQL = new SqlConnection(SQLConnString);
connectionToSQL.Open();
var wktbl = new DataTable();
var cmd = new SqlCommand("SELECT * FROM TAGS$",connectionToSQL);
var da = new SqlDataAdapter(cmd);
var b = new SqlCommandBuilder(da);
da.Fill(wktbl);
wktbl.Rows[3][2] = "5";
wktbl.AcceptChanges();
da.Update(wktbl);
Just skip the call to AcceptChanges and the code should work fine. It marks all rows as unmodified so there's nothing left to do for your Update call.
Okay, I would like to expand my question to my original effort...I select * from an Excel spreadsheet into dt. I want to take those values and update the SQL table. (the SQL table exists because of a manual import to SQL from the original Excel spreadsheet, has a primary key set, user updates the excel sheet, I need to update the SQL values.) I am setting the RowState to modified in an effort to invoke the Update.
connectionToSQL = new SqlConnection(SQLConnString);
connectionToSQL.Open();
var cmd = new SqlCommand("SELECT * FROM TAGS$",connectionToSQL);
var da = new SqlDataAdapter(cmd);
var b = new SqlCommandBuilder(da);
//dt.Rows[3][2] = "20";
foreach (DataRow r in dt.Rows)
{
r.SetModified();
}
da.Update(dt);
Related
I'm currently using Mono on Ubuntu with MonoDevelop, running with a DataTable matching a table in the database, and should be attempting to update it.
The code following uses a Dataset loaded from an XML file, which was created from a Dataset.WriteXML on another machine.
try
{
if(ds.Tables.Contains(s))
{
ds.Tables[s].AcceptChanges();
foreach(DataRow dr in ds.Tables[s].Rows)
dr.SetModified(); // Setting to modified so that it updates, rather than inserts, into the database
hc.Data.Database.Update(hc.Data.DataDictionary.GetTableInfo(s), ds.Tables[s]);
}
}
catch (Exception ex)
{
Log.WriteError(ex);
}
This is the code for inserting/updating into the database.
public override int SQLUpdate(DataTable dt, string tableName)
{
MySqlDataAdapter da = new MySqlDataAdapter();
try
{
int rowsChanged = 0;
int tStart = Environment.TickCount;
da.SelectCommand = new MySqlCommand("SELECT * FROM " + tableName);
da.SelectCommand.Connection = connection;
MySqlCommandBuilder cb = new MySqlCommandBuilder(da);
da.UpdateCommand = cb.GetUpdateCommand();
da.DeleteCommand = cb.GetDeleteCommand();
da.InsertCommand = cb.GetInsertCommand();
da.ContinueUpdateOnError = true;
da.AcceptChangesDuringUpdate = true;
rowsChanged = da.Update(dt);
Log.WriteVerbose("Tbl={0},Rows={1},tics={2},", dt.TableName, rowsChanged, Misc.Elapsed(tStart));
return rowsChanged;
catch (Exception ex)
{
Log.WriteError("{0}", ex.Message);
return -1
}
I'm trying the above code, and rowsChanged becomes 4183, the number of rows I'm editing. However, when I use HeidiSQL to check the database itself, it doesn't change anything at all.
Is there a step I'm missing?
Edit: Alternatively, being able to overwrite all rows in the database would work as well. This is a setup for updating remote computers using USB sticks, forcing it to match a source data table.
Edit 2: Added more code sample to show the source of the DT. The DataTable is prefilled in the calling function, and all rows have DataRow.SetModified(); applied.
Edit 3: Additional information. The Table is being filled with data from an XML file. Attempting fix suggested in comments.
Edit 4: Adding calling code, just in case.
Thank you for your help.
The simplest way which you may want to look into might be to TRUNCATE the destination table, then simply save the XML import to it (with AI off so it uses the imported ID if necessary). The only problem may be with the rights to do that. Otherwise...
What you are trying to do can almost be handled using the Merge method. However, it can't/won't know about deleted rows. Since the method is acting on DataTables, if a row was deleted in the master database, it will simply not exist in the XML extract (versus a RowState of Deleted). These can be weeded out with a loop.
Likewise, any new rows may get a different PK for an AI int. To prevent that, just use a simple non-AI PK in the destination db so it can accept any number.
The XML loading:
private DataTable LoadXMLToDT(string filename)
{
DataTable dt = new DataTable();
dt.ReadXml(filename);
return dt;
}
The merge code:
DataTable dtMaster = LoadXMLToDT(#"C:\Temp\dtsample.xml");
// just a debug monitor
var changes = dtMaster.GetChanges();
string SQL = "SELECT * FROM Destination";
using (MySqlConnection dbCon = new MySqlConnection(MySQLOtherDB))
{
dtSample = new DataTable();
daSample = new MySqlDataAdapter(SQL, dbCon);
MySqlCommandBuilder cb = new MySqlCommandBuilder(daSample);
daSample.UpdateCommand = cb.GetUpdateCommand();
daSample.DeleteCommand = cb.GetDeleteCommand();
daSample.InsertCommand = cb.GetInsertCommand();
daSample.FillSchema(dtSample, SchemaType.Source);
dbCon.Open();
// the destination table
daSample.Fill(dtSample);
// handle deleted rows
var drExisting = dtMaster.AsEnumerable()
.Select(x => x.Field<int>("Id"));
var drMasterDeleted = dtSample.AsEnumerable()
.Where( q => !drExisting.Contains(q.Field<int>("Id")));
// delete based on missing ID
foreach (DataRow dr in drMasterDeleted)
dr.Delete();
// merge the XML into the tbl read
dtSample.Merge(dtMaster,false, MissingSchemaAction.Add);
int rowsChanged = daSample.Update(dtSample);
}
For whatever reason, rowsChanged always reports as many changes as there are total rows. But changes from the Master/XML DataTable do flow thru to the other/destination table.
The delete code gets a list of existing IDs, then determines which rows needs to be deleted from the destination DataTable by whether the new XML table has a row with that ID or not. All the missing rows are deleted, then the tables are merged.
The key is dtSample.Merge(dtMaster,false, MissingSchemaAction.Add); which merges the data from dtMaster with dtSample. The false param is what allows the incoming XML changes to overwrite values in the other table (and eventually be saved to the db).
I have no idea whether some of the issues like non matching AI PKs is a big deal or not, but this seems to handle all that I could find. In reality, what you are trying to do is Database Synchronization. Although with one table, and just a few rows, the above should work.
I have 2 DataTables: 1 that is filled with all the data from a table in my database called Ticket_Report, and a second one that is filled with new tickets.
I am searching the Ticket_report datatable for duplicates from the new ticket DataTable (and deleting them). Then I merge the new tickets datatable into the Ticket_report datatable.
I then try and Update the Ticket_Report table in SQL Server with the newly edited Ticket_report datatable. I am expecting the Update method to Update the table in SQL Server with rows that have matching primary keys from the datatable, and Insert rows that don't exist.
I am not getting any errors, however it doesn't seem like the rows are being updated/inserted.
con.Open();
DataTable ticketReportDT = new DataTable();
ticketReportDT = newTicketdt.Clone();
ticketReportDT.Columns[0].Unique = true;
SqlCommand cmd2 = new SqlCommand("SELECT * FROM ticket_report", con);
SqlDataAdapter da = new SqlDataAdapter(cmd2);
da.Fill(ticketReportDT);
da.UpdateCommand = new SqlCommandBuilder(da).GetUpdateCommand();
int currentTicketCount = ticketReportDT.Rows.Count;//3234
int newTicketCount = newTicketdt.Rows.Count; //339
//Removing Duplicate tickets in ticketReportDt
foreach (DataRow NewTicketsRow in newTicketdt.Rows)
{
foreach (DataRow currentTicketsRow in ticketReportDT.Select())
{
if (currentTicketsRow.Field<string>(ticketReportDT.Columns[0]) == NewTicketsRow.Field<string>(newTicketdt.Columns[0]))
{
currentTicketsRow.Delete();
}
}
}
ticketReportDT.AcceptChanges();
int currentTicketCount2 = ticketReportDT.Rows.Count;//2903, is less than last count because duplicates removed
ticketReportDT.Merge(newTicketdt);//add new tickets to ticketReportDT
ticketReportDT.AcceptChanges();
int currentTicketCount3 = ticketReportDT.Rows.Count;//3242, count went up because new tickets added
da.Update(ticketReportDT);//apply changes to database table Ticket_Report
con.Close();
Console.WriteLine("Ticket Transfer Complete");
This runs without error. To test, I did a count query in SQL Server before and after this update.
Before update:
select count(*) from TICKET_REPORT
// = 3234
After Update:
select count(*) from TICKET_REPORT
// = 3234 <-Should be 3242 (row count of ticketReportDT)
It seems like the Datatable has the correct amount of rows, but when I do the update, this does not reflect in SQL Server. Am I doing something wrong?
Since you have called ticketReportDT.AcceptChanges() before updating database it is not going to update anything in the database.
i'm trying to add a new row to my datatable.
I've no error while running this code but nothing happened in my table.
Here's my code :
string table = "`DONNEE ENTRANT`";
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * From " + table, _conn);
OleDbCommandBuilder cmdBuilder = new OleDbCommandBuilder(adapter);
DataTable dataTable = new DataTable(table);
adapter.Fill(dataTable);
DataRow row = dataTable.NewRow();
row["CODE LIAISON"] = "TEST";
dataTable.Rows.Add(row);
dataTable.AcceptChanges();
adapter.Update(dataTable);
Any idea what i'm doing wrong (in this way, I know that we can run command with oleDb but really don't like this way ...).
Thanks
Based on what you're doing it appears you want that new row to end up in the database. So remove this line:
dataTable.AcceptChanges();
because that's changing the RowState to Unchanged and you need it left at Added. Further, you need to make sure that your adapter has an InsertStatement defined so it can use it.
I would use [] instead of `` but I believe the answer to correct your problem was already given by #Michael Perrenoud
I have a table which has some 100-200 records.
I have fetch those records into a dataset.
Now i am looping through all the records using foreach
dataset.Tables[0].AsEnumerable()
I want to update a column for each record in the loop. How can i do this. Using the same dataset.
I'm Assumng your using a Data Adapter to Fill the Data Set, with a Select Command?
To edit the data in your Data Table and save changes back to your database you will require an Update Command for you Data Adapter. Something like this :-
SQLConnection connector = new SQLConnection(#"Your connection string");
SQLAdaptor Adaptor = new SQLAdaptor();
Updatecmd = new sqlDbCommand("UPDATE YOURTABLE SET FIELD1= #FIELD1, FIELD2= #FIELD2 WHERE ID = #ID", connector);
You will also need to Add Parameters for the fields :-
Updatecmd.Parameters.Add("#FIELD1", SQLDbType.VarCHar, 8, "FIELD1");
Updatecmd.Parameters.Add("#FIELD2", SQLDbType.VarCHar, 8, "FIELD2");
var param = Updatecmd.Parameters.Add("#ID", SqlDbType.Interger, 6, "ID");
param.SourceVersion = DataRowVersion.Original;
Once you have created an Update Command with the correct SQL statement, and added the parameters, you need to assign this as the Insert Command for you Data Adapter :-
Adaptor.UpdateCommand = Updatecmd;
You will need to read up on doing this yourself, go through some examples, this is a rough guide.
The next step is to Enumerate through your data table, you dont need LINQ, you can do this :-
foreach(DataRow row in Dataset.Tables[0].Rows)
{
row["YourColumn"] = YOURVALUE;
}
One this is finished, you need to call the Update() method of yout Data Adapter like so :-
DataAdapter.Update(dataset.Tables[0]);
What happens here, is the Data Adapter calls the Update command and saves the changes back to the database.
Please Note, If wish to ADD new rows to the Database, you will require am INSERT Command for the Data Adapter.
This is very roughly coded out, from the top of my head, so the syntax may be slightly out. But will hopefully help.
You should use original DataAdapter (adapter in code below) that was used to fill DataSet and call Update method, you will need CommandBuilder also, it depends what DB you are using, here is the example for SQL server :
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
adapter.UpdateCommand = builder.GetUpdateCommand();
adapter.Update(dataset);
dataset.AcceptChanges();
Here is the good example :
http://support.microsoft.com/kb/307587
The steps would be something like:
- create a new DataColumn[^]
- add it to the data table's Columns[^] collection
- Create a DataRow [^] for example using NewRow[^]
- Modify the values of the row as per needed using Item[^] indexer
- add the row to Rows[^] collection
- after succesful modifications AcceptChanges[^]
Like this:
DataTable table = new DataTable();
table.Columns.Add("ID", typeof(int));
table.Columns.Add("ProductName");
table.Rows.Add(1, "Chai");
table.Rows.Add(2, "Queso Cabrales");
table.Rows.Add(3, "Tofu");
EnumerableRowCollection<DataRow> Rows = table.AsEnumerable();
foreach (DataRow Row in Rows)
Row["ID"] = (int)Row["ID"] * 2;
Add the column like below.
dataset.Tables[0].Columns.Add(new DataColumn ("columnname"));
Update the columns values like below.
for (int i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
dataset.Tables[0].Rows[i]["columnname"] = "new value here";
}
Update Database
dataset.AcceptChanges();
I've got an assignment which requires me to update the northwind database,
I've done everything like the tutorials say as follows
I fill The DataTable Using The DataAdapter.Fill(table).
I build the Delete,Insert,Update Commands using CommangBuilder
SqlDataAdapter adapter = new SqlDataAdapter(selectStr, conn);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
adapter.DeleteCommand = builder.GetDeleteCommand(true);
adapter.UpdateCommand = builder.GetUpdateCommand(true);
adapter.InsertCommand = builder.GetInsertCommand(true);
adapter.Fill(employees_table);
I also set a primary key for the table:
DataColumn[] employees_keys = new DataColumn[2];
employees_keys[0] = employees.Columns["EmployeeID"];
employees_table.PrimaryKey = employees_keys;
Now I've attempted to delete and add a row:
// accepts an employee object and creates a new new row with the appropriate values for
// an employee table row
DataRow row = ConvertEmployeeToRow(employeeToAdd);
employee_table.Rows.Add(row);`
and deleting a row:
DataRow row = employees.Rows.Find(employeeToDismiss.ID);
employees.Rows.Remove(row);
I should also point out that I've attempted to use row.SetAdded() and row.Delete()
Anyway, at the end when I try to update the database
int k = employees_adapter.Update(employees_table);
on added rows sometimes k get valued, on remove never, and in either case nothing really gets updated at all in the database itself.
Any insight of what I'm doing wrong?
Make sure you're calling employee_table.AcceptChanges() after the call to Update() to save the changes to the database.
Check if the CommandBuilder really makes an Update command for you, like this:
MessageBox.Show(adapter.UpdateCommand.CommandText);
If the primary key info is missing it won't build the update command at all!
I am little confuse here your SqlDataAdapter name is adapter and you are doing updation in employees_adapter.The steps are so simple to work with SqlDataAdapter just follow theses
Step No 1:
SqlDataAdapter adapter = new SqlDataAdapter(selectStr, conn);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
DataTable employees_table= new DataTable ();
adapter.Fill(employees_table);
Step No 2:
After you got the data in dataset start manipulation on it..
To insert :
DataRow MyRow = employees_table.NewRow();
//Now Fill data in MyRow
employees_table.Tables[0].Rows.Add(MyRow);
employees_table.AcceptChanges();
adapter.Update(employees_table);
To Delete :
/get only the rows you want
DataRow[] result = employees_table.Select("ID ="+id); //id will be provided by you
//Now do here data updation
employees_table.AcceptChanges()
adapter.Update(employees_table);
Like wise you can apply updation..But after doing any changes must call
table.AcceptChanges() and then'adapter.Update(employees_table)'