从表中删除行而不检查它们是否存在

时间:2014-10-01 08:04:17

标签: c# .net sql-server datatable tableadapter

我有一个接受DataTable的WCF服务,并将它们合并到现有数据中。以前,这只需要添加行,这可以很好地工作,但是有了删除行的新要求(无论它们是否存在),我遇到了问题。

由于有问题的行数量非常大,无论是在SQL服务器还是在DataTable中,我都不想加载现有行并将它们与my {进行比较{1}}。

我的代码执行以下操作:

DataTable

现在,我(或许天真地)想要添加,如果一行不存在,它将被默默地忽略,或者最坏的情况下,设置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; } 属性,但不是。相反,行

HasErrors

引发异常changesApplied = barAdapter.Update(ds.Bar); ,并显示以下消息:“并发冲突:DeleteCommand影响预期的1条记录中的0条。”

我可以看到为什么当你关心并发时这是一个很好的通知,但我不需要。我只想删除该行,或忽略它丢失。

1 个答案:

答案 0 :(得分:2)

根据此问题,

Here是一篇有用的文章。引用:

  

如果DataAdapter执行更新命令并检测到   受影响的行数为0,它会抛出DBConcurrencyException。该   整个更新操作将被中止,并且没有更多的行   将检查DataSet。通常,会发生DBConcurrencyException   其中一个原因是:

  • 您错误地为自定义UPDATE,INSERT或DELETE命令编写了SQL。
  • 无法找到该行,因为用于查找该行的信息与当前值不匹配。自上次检索信息以来,此问题表明另一个用户已更改该行。

第二个是你想忽略的问题。

处理错误有两种选择。一种选择是处理在执行命令之后但在引发错误之前触发的DataAdapter.RowUpdated事件。您可以使用此事件处理程序来记录问题,并以编程方式指示DataAdapter忽略该错误并继续处理其他错误。这是一个显示和跳过所有错误的示例:

protected void OnRowUpdated(object sender, SqlRowUpdatedEventArgs e) // handles DataAdapter.RowUpdated
{
    // Check how many records were affected. ' If no records were affected, there was an error. 
    if (e.RecordsAffected == 0) {
        // log?
        // Don't throw an exception, continue with following 
        e.Status = UpdateStatus.SkipCurrentRow;
    }
}

另一个更简单的选择是将DataAdapter.ContinueUpdateOnError属性设置为true。然后,在更新完成后,您可以调查错误,记录错误或将其显示给用户。 DataAdapter将尝试每次更改。

barAdapter.ContinueUpdateOnError = true; 

由于您使用的是强类型TableAdapter,它只保留DataAdapter protected属性,因此您无法直接更改此设置。你可以做的是扩展这个自动生成的类(它是partial class)。因此,在同一目录中创建另一个具有相同名称的类,例如:public partial class BarTableAdapter

现在,您可以创建可以访问DataDapter的新属性或方法。请注意,该类必须位于相同(自动生成)的命名空间中。例如:

namespace ApplicationName.DataSetNameTableAdapters
{
    public partial class BarTableAdapter 
    {
        public bool ContinueUpdateOnError
        {
            get
            {
                return this.Adapter.ContinueUpdateOnError;
            }
            set
            {
                this.Adapter.ContinueUpdateOnError = value;
            }
        }
    }
}

不要扩展原始类(.designer.cs),它将在设计器的每次更改时被覆盖。

现在你可以做到:

BarTableAdapter barAdapter = new BarTableAdapter();
barAdapter.ContinueUpdateOnError = true;
changesApplied = barAdapter.Update(ds.Bar);