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.
Related
Below is my code to get data from my oracle database to display a table with multiple rows in asp.net(C#). Te columns will be Name, Section and Gender. The headers of the table are hardcoded, only rows' data should be populated from database. On executing the code, I am getting only 1st row coming from database. Remaining rows are not coming. Please suggest for the solution.
public void GetDailyData()
{
using (OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings["dataconn"].ToString()))
{
try
{
string query = #"SELECT name,section, gender FROM t_student WHERE order by TRUNC(admissionDate)";
OracleCommand cmd = new OracleCommand(query, conn);
conn.Open();
OracleDataAdapter da = new OracleDataAdapter(cmd);
DataSet ds = new DataSet();
cmd.ExecuteNonQuery();
da.Fill(ds);
foreach (DataRow dr in ds.Tables[0].Rows)
{
if (ds.Tables[0].Rows.Count > 0)
{
LabelName.Text = ds.Tables[0].Rows[0].Field<string>(0);
LabelSection.Text = ds.Tables[0].Rows[0].Field<string>(1) ;
LabelGender.Text = ds.Tables[0].Rows[0].Field<string>(2) ;
}
}
}
catch (Exception ex)
{
throw ex;
}
}
}
You're only seeing row data from the first row because that's what you're pulling out when you say ds.Tables[0].Rows[0] - Rows[0] will always be the first row of the table
This entire block of code is confused;
you cannot show multiple rows using single labels - Use a Grid component and DataBind it to the datatable.
The code uses a loop to go through table rows but checks if the table has rows, inside the loop ( the loop won't run if it doesn't) and instead of using the enumerated row it always access the first row on every pass of the loop.
Do not use a DataSet, just make a new DataTable and fill it - datasets are for when you want to work with multiple related datatables and in this case of a single table are a useless extra layer.
Do not ExecuteNonQuery on the command, it's a useless operation - the dataadapter will execute the query during the fill, you don't need to do it (and ExecuteNonQuery is for insert/update/delete/create etc - this is a select).
Your code could/should look more like:
DataTable dt = new DataTable();
da.Fill(dt);
gridControl.DataSource = dt;
gridControl.DataBind();
That's it. All the rest of the code (apart from the command and connection) should be thrown away
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 am trying to edit DataTable Filled by NpgsqlDataAdapter.
After calling Fill() method, I have only one row in DataTable. Then I changed value of one column only and tried to update as below.
Then I am getting this error:
DBConcurrencyException occured
My code is:
NpgsqlDataAdapter getAllData = new NpgsqlDataAdapter("SELECT sn,
code,product, unitprice, quantity, InvoiceNo, Date FROM stocktable WHERE Code='" + product + "'
ORDER BY EDate ASC", DatabaseConnectionpg);
DataTable ds1 = new DataTable();
ds1.Clear();
getAllData.Fill(ds1);
if (ds1.Rows.Count > 0)
{
ds1.Rows[0]["Quantity"] = qty;// calculated value
}
ds1 = ds1.GetChanges();
NpgsqlCommandBuilder cb = new NpgsqlCommandBuilder(getAllData);
//getAllData.RowUpdating += (sender2, e2) => { e2.Command.Parameters.Clear(); };
//cb.SetAllValues = false;
getAllData.DeleteCommand = cb.GetDeleteCommand();
getAllData.InsertCommand = cb.GetInsertCommand();
getAllData.UpdateCommand = cb.GetUpdateCommand();
int x = getAllData.Update(ds1);
if (x > 0)
{
ds1.AcceptChanges();
}
EDIT: I have three fields as primary keys and I am calling only two fields in select statement. Is it reason for DBConcurrency error? But I am able to update the table with same (three fields as primary key) parameters in SQL Server 2005.
UPDATE:
I found the solution and the solution is
I created and used second DataAdapter to update data.
I used getAllData(NpgSqlDataAdapter) To fill table as
NpgsqlDataAdapter getAllData = new NpgsqlDataAdapter("SELECT
code,product, unitprice, quantity, InvoiceNo, Date FROM stocktable WHERE Code='" + product + "'
ORDER BY EDate ASC", DatabaseConnectionpg);
And Also created next Adapter to update as
NpgsqlDataAdapter updateadap= new NpgsqlDataAdapter("SELECT sn, quantity FROM stocktable WHERE Code='" + product + "'
ORDER BY EDate ASC", DatabaseConnectionpg);
NpgsqlCommandBuilder cb = new NpgsqlCommandBuilder(updateadap);
//getAllData.RowUpdating += (sender2, e2) => { e2.Command.Parameters.Clear(); };
//cb.SetAllValues = false;
updateadap.DeleteCommand = cb.GetDeleteCommand();
updateadap.InsertCommand = cb.GetInsertCommand();
updateadap.UpdateCommand = cb.GetUpdateCommand();
int x = updateadap.Update(ds1);
if (x > 0)
{
......
}
I tried alot and found that NpgsqlDataAdapter had problem with Column Code. When i ommited it then it worked. DataType of column code is varchar. I don't know why this was happening. Anybody has idea about it?
This is because DataAdapter uses Optimistic Concurrency by default. This means that if you are trying to update a row that no longer exists in the database or changed, the update from the DataAdapter will fail with the exception above.
Possible scenarios:
Between you selecting the data into the client and sending the
update, another user is deleting or updating this row from his application.
It can be that you are deleting the data from somewhere else in your application.
For example:
You fill the DataTable that will be used for the update.
Deletes the row with Code = 1101 (for example) directly from the database, i.e. you do not use the DataTable here. This is emulating another user deleting the row with Code = 1101 from another application. Or some other part in your code deleting the row with Code = 1101.
Selects out the row with Code = 1101 from the DataTable, this is just to show that it is still there even though you have deleted it from the database itself.
Edits the Quantity column in the row with Code = 1101 in the DataTable. This has to be done, otherwise the call to Update will ignore this row when updating.
Executes the update, this will throw the exception since you are trying to update a row that (no longer) exists in the database.
If you want to implement Last Writer Wins, Add the following code:
cb.ConflictOption = ConflictOption.OverwriteChanges;
Also there is one more possible thing : if you have Decimal/numeric as columns in the DB they may cause this error even though the data looks the same. This is due to a decimal rounding error.
An important note:
You should always use parameterized queries by the way. This kind of string concatenations are open for SQL Injection.
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);
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)'