【问题标题】:Deleting specific rows from DataTable从 DataTable 中删除特定行
【发布时间】:2011-04-13 11:21:34
【问题描述】:

我想从 DataTable 中删除一些行,但它给出了这样的错误,

集合已修改;枚举操作可能不会执行

我用来删除这段代码,

foreach(DataRow dr in dtPerson.Rows){
    if(dr["name"].ToString()=="Joe")
        dr.Delete();
}

那么,问题是什么以及如何解决?您建议哪种方法?

【问题讨论】:

    标签: c# delete-row


    【解决方案1】:

    如果您从集合中删除项目,则该集合已更改,您无法继续枚举它。

    改为使用 For 循环,例如:

    for(int i = dtPerson.Rows.Count-1; i >= 0; i--)
    {
        DataRow dr = dtPerson.Rows[i];
        if (dr["name"] == "Joe")
            dr.Delete();
    }
    dtPerson.AcceptChanges();
    

    请注意,您正在反向迭代以避免在删除当前索引后跳过一行。

    【讨论】:

    • @Slugster 打败了我! (我将您的 [ii] 更改为 [i],但是 :-)
    • 这是不正确的。您可以在删除行时使用 foreach 循环遍历表。见answer by Steve
    • 这个答案还应该包括@bokkie 的答案。如果我们稍后使用DataTable,它会抛出异常。正确的方法是在源 DataTable - dtPerson.Rows.Remove(dr) 上调用 Remove()
    • 如果您使用 DataTable 更新数据库服务器中的表,@Steve 有更好的答案。您可以在一个循环中将行标记为已删除、更新行和添加新行。您可以使用 SqlAdapter 将更改提交到 Db 表。考虑到问题出现的频率,整个过程比你想象的要复杂得多,但它确实有效。如果我不打算利用 DataTable 的事务性质,我只会使用对象集合和 namco 或 Widor 方法。
    • 不使用Delete() 需要调用AcceptChanges() 才能使删除生效?
    【解决方案2】:

    在每个人都加入“您不能删除枚举中的行”潮流之前,您需要首先意识到 DataTables 是事务性,并且在调用 AcceptChanges()

    之前不要从技术上清除更改

    如果您在调用 Delete 时看到此异常,则您已处于待更改数据状态。例如,如果您刚刚从数据库中加载,如果您处于 foreach 循环中,则调用 Delete 会引发异常。

    但是!但是!

    如果您从数据库中加载行并调用函数“AcceptChanges()”,您会将所有这些未决更改提交到 DataTable。现在您可以遍历调用 Delete() 的行列表而无需担心,因为它只是将行标记为删除,但在您再次调用 AcceptChanges 之前不会提交()

    我意识到这个回复有点过时,但我最近不得不处理一个类似的问题,希望这可以为未来开发 10 年代码的开发人员节省一些痛苦:)


    附:下面是Jeff添加的简单代码示例:

    C#

    YourDataTable.AcceptChanges(); 
    foreach (DataRow row in YourDataTable.Rows) {
        // If this row is offensive then
        row.Delete();
    } 
    YourDataTable.AcceptChanges();
    

    VB.Net

    ds.Tables(0).AcceptChanges()
    For Each row In ds.Tables(0).Rows
        ds.Tables(0).Rows(counter).Delete()
        counter += 1
    Next
    ds.Tables(0).AcceptChanges()
    

    【讨论】:

    • c#版本只需要使用{和}代替()
    • 也更有帮助(我认为)将object row_loopVariable in ds.Tables(0).Rows更改为DataRow row in ds.Tables(0).Rows
    • Ffs,这在噩梦般的周末部署中拯救了我。你应该得到所有的啤酒!
    • 不错的代码。一件事,在 C# 中,加一的典型方法是 counter++ 而不是 counter+= 1
    【解决方案3】:

    使用此解决方案:

    for(int i = dtPerson.Rows.Count-1; i >= 0; i--) 
    { 
        DataRow dr = dtPerson.Rows[i]; 
        if (dr["name"] == "Joe")
            dr.Delete();
    } 
    

    如果你要在删除行后使用数据表,你会得到一个错误。所以你可以做的是: 将dr.Delete(); 替换为dtPerson.Rows.Remove(dr);

    【讨论】:

      【解决方案4】:

      这对我有用,

      List<string> lstRemoveColumns = new List<string>() { "ColValue1", "ColVal2", "ColValue3", "ColValue4" };
      List<DataRow> rowsToDelete = new List<DataRow>();
      
      foreach (DataRow row in dt.Rows) {
          if (lstRemoveColumns.Contains(row["ColumnName"].ToString())) {
              rowsToDelete.Add(row);
          }
      }
      
      foreach (DataRow row in rowsToDelete) {
          dt.Rows.Remove(row);
      }
      
      dt.AcceptChanges();
      

      【讨论】:

      • 这么容易错过dt.AcceptChanges()
      • "你也可以调用DataRow类的Delete方法,只标记要删除的行。调用Remove与调用Delete然后调用AcceptChanges是一样的。remove不应该在foreach循环中调用在遍历 DataRowCollection 对象时。Remove 会修改集合的状态。”请参阅msdn.microsoft.com/de-de/library/… 干杯。
      【解决方案5】:
      DataRow[] dtr=dtPerson.select("name=Joe");
      foreach(var drow in dtr)
      {
         drow.delete();
      }
      dtperson.AcceptChanges();
      

      希望对你有帮助

      【讨论】:

      • 命令是drow.Delete(); 而不是drow.delete(); 方法在.net btw 中区分大小写
      【解决方案6】:

      要从 DataTable 中删除 整行,请这样做

      DataTable dt = new DataTable();  //User DataTable
      DataRow[] rows;
      rows = dt.Select("UserName = 'KarthiK'");  //'UserName' is ColumnName
      foreach (DataRow row in rows)
           dt.Rows.Remove(row);
      

      【讨论】:

        【解决方案7】:

        或者只是将 DataTable 行集合 转换为列表:

        foreach(DataRow dr in dtPerson.Rows.ToList())
        {
            if(dr["name"].ToString()=="Joe")
            dr.Delete();
        }
        

        【讨论】:

          【解决方案8】:

          问题出在哪里:禁止在 foreach 循环内从集合中删除项目。

          解决方案:要么像 Widor 写的那样做,要么使用两个循环。在第一次通过 DataTable 时,您只存储(在临时列表中)对要删除的行的引用。然后在第二次遍历临时列表时删除这些行。

          【讨论】:

            【解决方案9】:
            <asp:GridView ID="grd_item_list" runat="server" AutoGenerateColumns="false" Width="100%" CssClass="table table-bordered table-hover" OnRowCommand="grd_item_list_RowCommand">
                <Columns>
                    <asp:TemplateField HeaderText="No">
                        <ItemTemplate>
                            <%# Container.DataItemIndex + 1 %>
                        </ItemTemplate>
                    </asp:TemplateField>            
                    <asp:TemplateField HeaderText="Actions">
                        <ItemTemplate>                    
                            <asp:Button ID="remove_itemIndex" OnClientClick="if(confirm('Are You Sure to delete?')==true){ return true;} else{ return false;}" runat="server" class="btn btn-primary" Text="REMOVE" CommandName="REMOVE_ITEM" CommandArgument='<%# Container.DataItemIndex+1 %>' />
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
            
             **This is the row binding event**
            
            protected void grd_item_list_RowCommand(object sender, GridViewCommandEventArgs e) {
            
                item_list_bind_structure();
            
                if (ViewState["item_list"] != null)
                    dt = (DataTable)ViewState["item_list"];
            
            
                if (e.CommandName == "REMOVE_ITEM") {
                    var RowNum = Convert.ToInt32(e.CommandArgument.ToString()) - 1;
            
                    DataRow dr = dt.Rows[RowNum];
                    dr.Delete();
            
                }
            
                grd_item_list.DataSource = dt;
                grd_item_list.DataBind();
            }
            

            【讨论】:

              【解决方案10】:

              我知道这是一个非常古老的问题,几天前我也遇到过类似的情况。

              问题是,在我的表中大约是。 10000 行,所以循环通过DataTable 行非常慢。

              最后,我找到了更快的解决方案,我将源 DataTable 复制到所需的结果,将源 DataTablemerge 的结果从临时 DataTable 清除到源之一。

              注意 : 改为在 DataRow 中搜索 Joe 称为 name 您必须搜索所有没有名称为 Joe 的记录(搜索方式有点相反)

              有例子(vb.net):

              'Copy all rows into tmpTable whose not contain Joe in name DataRow
              Dim tmpTable As DataTable = drPerson.Select("name<>'Joe'").CopyToTable
              'Clear source DataTable, in Your case dtPerson
              dtPerson.Clear()
              'merge tmpTable into dtPerson (rows whose name not contain Joe)
              dtPerson.Merge(tmpTable)
              tmpTable = Nothing
              

              我希望这个更短的解决方案能对某人有所帮助。

              c#代码(不确定是否正确,因为我使用了在线转换器:():

              //Copy all rows into tmpTable whose not contain Joe in name DataRow
              DataTable tmpTable = drPerson.Select("name<>'Joe'").CopyToTable;
              //Clear source DataTable, in Your case dtPerson
              dtPerson.Clear();
              //merge tmpTable into dtPerson (rows whose name not contain Joe)
              dtPerson.Merge(tmpTable);
              tmpTable = null;
              

              当然,我使用Try/Catch 以防万一没有结果(例如,如果您的dtPerson 不包含name Joe 它会抛出异常),所以您对您的表什么也不做,它保持不变。

              【讨论】:

                【解决方案11】:

                我的应用程序中有一个数据集,我去设置更改(删除一行),但 ds.tabales["TableName"] 是只读的。然后我找到了这个解决方案。

                这是一个 wpf C# 应用程序,

                try {
                    var results = from row in ds.Tables["TableName"].AsEnumerable() where row.Field<string>("Personalid") == "47" select row;                
                    foreach (DataRow row in results) {
                        ds.Tables["TableName"].Rows.Remove(row);                 
                    }           
                }
                

                【讨论】:

                  【解决方案12】:

                  你尝试这个从数据表中获取和删除 id 列

                  if (dt1.Columns.Contains("ID"))
                  {
                      for (int i = dt1.Rows.Count - 1; i >= 0; i--)
                      {
                          DataRow dr = dt1.Rows[i];
                  
                          if (dr["ID"].ToString() != "" && dr["ID"].ToString() != null)
                          {
                              dr.Delete();
                          }
                      }
                  
                      dt1.Columns.Remove("ID");
                  }
                  

                  【讨论】:

                    【解决方案13】:

                    我在这里看到了正确答案的各种点点滴滴,但让我把它们放在一起并解释几件事。

                    首先,AcceptChanges 应该只用于将表上的整个事务标记为已验证并已提交。这意味着如果您使用 DataTable 作为数据源来绑定到例如 SQL 服务器,那么手动调用 AcceptChanges 将保证更改永远不会保存到 SQL 服务器

                    让这个问题更令人困惑的是,实际上有两种情况会引发异常,我们必须阻止这两种情况。

                    1.修改 IEnumerable 的集合

                    我们不能向被枚举的集合添加或删除索引,因为这样做可能会影响枚举器的内部索引。 有两种方法可以解决这个问题:要么在 for 循环中进行自己的索引,要么使用单独的集合(未修改)进行枚举。

                    2。尝试读取已删除的条目

                    由于 DataTables 是 事务性 集合,因此可以将条目标记为删除,但仍会出现在枚举中。这意味着如果您要求删除列 "name" 的条目,那么它将引发异常。 这意味着我们必须在查询列之前检查是否为dr.RowState != DataRowState.Deleted

                    把它们放在一起

                    我们可能会弄得一团糟并手动完成所有这些工作,或者我们可以让 DataTable 为我们完成所有工作,并通过执行以下操作使语句看起来更像 SQL 调用:

                    string name = "Joe";
                    foreach(DataRow dr in dtPerson.Select($"name='{name}'"))
                        dr.Delete();
                    

                    通过调用DataTable 的Select 函数,我们的查询会自动避免DataTable 中已删除的条目。由于Select 函数返回一个匹配数组,所以当我们调用dr.Delete() 时,我们枚举的集合不会被修改。我还为 Select 表达式添加了字符串插值,以便在不使代码嘈杂的情况下进行变量选择。

                    【讨论】:

                      【解决方案14】:

                      在按钮中使用它的简单方法:

                       var table = $('#example1').DataTable();
                       table.row($(`#yesmediasec-${id}`).closest('tr')).remove( ).draw();
                      

                      example1 = id 表。 yesmediasec = 行中按钮的id

                      使用它,一切都会好起来的

                      【讨论】:

                      • 问题是关于 C# 而不是 jQuery 插件
                      猜你喜欢
                      • 2016-07-31
                      • 1970-01-01
                      • 2015-06-13
                      • 2015-02-09
                      • 2021-04-28
                      • 2023-04-05
                      • 1970-01-01
                      • 2015-02-23
                      • 2011-10-24
                      相关资源
                      最近更新 更多