I have a WCF service that accepts a DataTable
, and merges them into the existing data. Previously, this has just required adding rows, which works beautifully, but with this new requirement of deleting rows (whether or not they actually exist), I'm running into a problem.
Due to the fact that the amount of rows in question can be quite large, both in the SQL server and in the DataTable
, I do not want to have to load in existing rows and compare them with my DataTable
.
My code does the following:
public Statistics ApplyChanges(DataTable changeData)
{
var stats = new Statistics();
if (changeData.IsEmpty)
{
Trace.WriteLine(string.Format("Client {0} had nothing to do; called ApplyChanges anyway. (Should normally not happen.)", ClientId));
return stats;
}
FooDataSet ds = new FooDataSet();
ds.Bar.Merge(changeData, false, MissingSchemaAction.Ignore);
foreach (var row in ds.Bar)
{
// This is the new requirement. If the incoming row's 'Value' is null,
// delete the row from the database, or, if the row doesn't exist, do
// nothing.
if (row.Field<string>("Value") == null)
row.Delete();
else
row.SetAdded();
}
int changesApplied;
using (var scope = new TransactionScope())
{
BarTableAdapter barAdapter = new BarTableAdapter();
changesApplied = barAdapter.Update(ds.Bar);
scope.Complete();
}
stats.ChangesApplied = changesApplied;
stats.ChangesFailed = ds.Bar.Count(r => r.HasErrors);
Trace.WriteLine(string.Format("Client {0} applied {1} changes, had {2} changes fail.", ClientId, changesApplied, stats.ChangesFailed));
return stats;
}
Now, I (perhaps naïvely) thought like with adding, that if a row didn't exist, it would either be silently ignored, or at the worst, have the HasErrors
property set, but no. Instead, the line
changesApplied = barAdapter.Update(ds.Bar);
Throws an exception, DBConcurrencyException
, with the following message: "Concurrency violation: the DeleteCommand affected 0 of the expected 1 records."
I can see why that's a nice notification to get when you care about concurrency, but I don't need to. I just want to either delete the row, or ignore that it's missing.