从 DataTable 中删除特定行

发布于 2024-11-01 00:29:35 字数 271 浏览 1 评论 0原文

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

集合已修改;枚举操作可能无法执行

我用于删除此代码的

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

,那么,问题是什么以及如何修复它?您建议采用哪种方法?

I want to delete some rows from DataTable, but it gives an error like this,

Collection was modified; enumeration operation might not execute

I use for deleting this code,

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

So, what is the problem and how to fix it? Which method do you advise?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

紫轩蝶泪 2024-11-08 00:29:36

这对我有用,

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

This works for me,

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();
榕城若虚 2024-11-08 00:29:36
DataRow[] dtr = dtPerson.Select("name=Joe"); //name is the column in the data table
foreach(var drow in dtr)
{
   drow.Delete();
}
dtperson.AcceptChanges();
DataRow[] dtr = dtPerson.Select("name=Joe"); //name is the column in the data table
foreach(var drow in dtr)
{
   drow.Delete();
}
dtperson.AcceptChanges();
王权女流氓 2024-11-08 00:29:36

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

To remove entire row from DataTable , do like this

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);
澜川若宁 2024-11-08 00:29:36

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

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

Or just convert a DataTable Row collection to a list:

foreach(DataRow dr in dtPerson.Rows.ToList())
{
    if(dr["name"].ToString()=="Joe")
    dr.Delete();
}
岁月静好 2024-11-08 00:29:36

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

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

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

1.修改 IEnumerable 的集合

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

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

由于 DataTable 是事务性集合,因此可以将条目标记为删除,但仍会出现在枚举中。这意味着,如果您询问“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 表达式增添了趣味,以允许变量选择而不会使代码变得嘈杂。

I'm seeing various bits and pieces of the right answer here, but let me bring it all together and explain a couple of things.

First of all, AcceptChanges should only be used to mark the entire transaction on a table as being validated and committed. Which means if you are using the DataTable as a DataSource for binding to, for example, an SQL server, then calling AcceptChanges manually will guarantee that that the changes never get saved to the SQL server.

What makes this issue more confusing is that there are actually two cases in which the exception is thrown and we have to prevent both of them.

1. Modifying an IEnumerable's Collection

We can't add or remove an index to the collection being enumerated because doing so may affect the enumerator's internal indexing.
There are two ways to get around this: either do your own indexing in a for loop, or use a separate collection (that is not modified) for the enumeration.

2. Attempting to Read a Deleted Entry

Since DataTables are transactional collections, entries can be marked for deletion but still appear in the enumeration. Which means that if you ask a deleted entry for the column "name" then it will throw an exception.
Which means we must check to see whether dr.RowState != DataRowState.Deleted before querying a column.

Putting it all together

We could get messy and do all of that manually, or we can let the DataTable do all the work for us and make the statement look and at more like an SQL call by doing the following:

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

By calling DataTable's Select function, our query automatically avoids already deleted entries in the DataTable. And since the Select function returns an array of matches, the collection we are enumerating over is not modified when we call dr.Delete(). I've also spiced up the Select expression with string interpolation to allow for variable selection without making the code noisy.

北音执念 2024-11-08 00:29:36

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

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

Where is the problem: It is forbidden to delete items from collection inside a foreach loop.

Solution: Either do it like Widor wrote, or use two loops. In the first pass over DataTable you only store (in a temporary list) the references to rows you want to delete. Then in the second pass over your temporary list you delete those rows.

盗梦空间 2024-11-08 00:29:36
<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();
}
<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();
}
已下线请稍等 2024-11-08 00:29:36

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

问题是,我的表中大约有。 10000 行,因此循环 DataTable 行非常慢。

最后,我找到了更快的解决方案,其中我复制了具有所需结果的源 DataTable,清除源 DataTable 并从临时 合并 结果>DataTable 进入源一。

注意:而是在名为nameDataRow中搜索Joe,您必须搜索没有名称<的所有记录< code>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 它会抛出异常),所以您对您的表不执行任何操作,它保持不变。

I know this is, very, old question, and I have similar situation few days ago.

Problem was, in my table are approx. 10000 rows, so looping trough DataTable rows was very slow.

Finally, I found much faster solution, where I make copy of source DataTable with desired results, clear source DataTable and merge results from temporary DataTable into source one.

note : instead search for Joe in DataRow called name You have to search for all records whose not have name Joe (little opposite way of searching)

There is example (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

I hope so this shorter solution will help someone.

There is c# code (not sure is it correct because I used online converter :( ):

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

Of course, I used Try/Catch in case if there is no result (for example, if Your dtPerson don't contain name Joe it will throw exception), so You do nothing with Your table, it stays unchanged.

凹づ凸ル 2024-11-08 00:29:36

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

You try this for getting and removing id column from data table

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");
}
愁杀 2024-11-08 00:29:36

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

I have a dataset in my app and I went to set changes (deleting a row) to it but ds.tabales["TableName"] is read only. Then I found this solution.

It's a wpf C# app,

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);                 
    }           
}
灯下孤影 2024-11-08 00:29:36

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

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

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

使用它,一切都会好的

the easy way use this in button :

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

example1 = id table .
yesmediasec = id of the button in the row

use it and every thing will be ok

泪是无色的血 2024-11-08 00:29:35

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

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

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

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

If you delete an item from a collection, that collection has been changed and you can't continue to enumerate through it.

Instead, use a For loop, such as:

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

Note that you are iterating in reverse to avoid skipping a row after deleting the current index.

烟雨扶苏 2024-11-08 00:29:35

在每个人都加入“您无法删除枚举中的行”的潮流之前,您需要首先认识到数据表是事务性的,并且在调用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()

Before everyone jumps on the 'You can't delete rows in an Enumeration' bandwagon, you need to first realize that DataTables are transactional, and do not technically purge changes until you call AcceptChanges()

If you are seeing this exception while calling Delete, you are already in a pending-changes data state. For instance, if you have just loaded from the database, calling Delete would throw an exception if you were inside a foreach loop.

BUT! BUT!

If you load rows from the database and call the function 'AcceptChanges()' you commit all of those pending changes to the DataTable. Now you can iterate through the list of rows calling Delete() without a care in the world, because it simply ear-marks the row for Deletion, but is not committed until you again call AcceptChanges()

I realize this response is a bit dated, but I had to deal with a similar issue recently and hopefully this saves some pain for a future developer working on 10-year-old code :)


P.s. Here is a simple code example added by 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()
半葬歌 2024-11-08 00:29:35

使用此解决方案:

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

with this solution:

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

if you are going to use the datatable after deleting the row, you will get an error. So what you can do is:
replace dr.Delete(); with dtPerson.Rows.Remove(dr);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文