繁体   English   中英

从数据表中删除特定行

[英]Deleting specific rows from DataTable

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

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

我用于删除此代码,

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

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

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

相反,使用 For 循环,例如:

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

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

在每个人都跳上“您不能删除枚举中”的潮流之前,您需要首先意识到 DataTables 是事务性的,并且在调用AcceptChanges()之前不要从技术上清除更改

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

但! 但!

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

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


Ps 这是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()

使用此解决方案:

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);

这对我有用,

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();
DataRow[] dtr=dtPerson.select("name=Joe");
foreach(var drow in dtr)
{
   drow.delete();
}
dtperson.AcceptChanges();

我希望它会帮助你

要从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);

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

foreach(DataRow dr in dtPerson.Rows.ToList())
{
    if(dr["name"].ToString()=="Joe")
    dr.Delete();
}
<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();
}

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

问题是,在我的桌子上大约是。 10000 行,因此循环遍历DataTable行非常慢。

最后,我找到了更快的解决方案,在该解决方案中,我复制了具有所需结果的源DataTable ,清除源DataTable并将临时DataTable结果merge到源DataTable

注意:而是在名为name DataRow搜索Joe您必须搜索所有没有姓名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 ,它将抛出异常),因此您对您的表不做任何操作,它保持不变。

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

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

我的应用程序中有一个数据集,我去设置更改(删除一行),但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);                 
    }           
}

您尝试使用此方法从数据表中获取和删除 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");
}

我在这里看到了正确答案的各种零碎部分,但让我把它们放在一起并解释一些事情。

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

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

1.修改一个IEnumerable的集合

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

2. 尝试阅读已删除的条目

由于数据表是事务性集合,条目可以被标记为删除,但仍会出现在枚举中。 这意味着如果您向已删除的条目询问列"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 表达式添加了字符串插值,以允许在不使代码嘈杂的情况下进行变量选择。

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

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

示例 1 = id 表。 yesmediasec = 行中按钮的 id

使用它,一切都会好的

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM