我想从DataTable中删除一些行,但它给出了这样的错误,
集合已修改;枚举操作可能无法执行
我用来删除此代码,
foreach(DataRow dr in dtPerson.Rows){
if(dr["name"].ToString()=="Joe")
dr.Delete();
}
那么,问题出在哪里,如何解决?您建议哪种方法?
Answers:
如果您从集合中删除项目,则该集合已被更改,无法继续枚举它。
而是使用For循环,例如:
for(int i = dtPerson.Rows.Count-1; i >= 0; i--)
{
DataRow dr = dtPerson.Rows[i];
if (dr["name"] == "Joe")
dr.Delete();
}
dtPerson.AcceptChanges();
请注意,您要反向进行迭代,以避免在删除当前索引后跳过行。
DataTable
后者,它将抛出异常。正确的方法是调用Remove()
源DataTable
- dtPerson.Rows.Remove(dr)
。
Delete()
不需要调用AcceptChanges()
才能使删除生效吗?
在每个人都跳入“您无法删除Enumeration中的行”潮流之前,您需要首先意识到DataTables是事务性的,并且从技术上讲,不要清除更改,直到您调用AcceptChanges()
如果在调用Delete时看到此异常,则您已经处于等待更改数据状态。例如,如果您刚从数据库中加载,则如果您在foreach循环中,则调用Delete会引发异常。
但!但!
如果从数据库加载行并调用函数“ AcceptChanges() ”,则会将所有这些未完成的更改提交到DataTable。现在您可以遍历调用Delete()的行列表,而无需担心,因为它只是将行标记为Deletion,但直到再次调用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()
object row_loopVariable in ds.Tables(0).Rows
为DataRow row in ds.Tables(0).Rows
counter++
代替counter+= 1
。
这对我有用
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();
希望对您有帮助
drow.Delete();
不是drow.delete();
方法在.net btw中区分大小写
<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
和merge
临时结果DataTable
到源代码一。
注意:不是搜索Joe
在DataRow
叫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
它会抛出异常),那么您对表不执行任何操作,则它保持不变。
我的应用程序中有一个数据集,我去设置了更改(删除一行),但是 ds.tabales["TableName"]
是只读的。然后我找到了解决方案。
这是一个wpfC#
应用
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);
}
}
我在这里看到了正确答案的各种点滴,但让我将它们汇总并解释几件事。
首先,AcceptChanges
仅应将标记在表上的整个事务标记为已验证并已提交。这意味着,如果您将DataTable用作绑定到例如SQL Server的数据源,则AcceptChanges
手动调用将确保这些更改永远不会保存到SQL Server中。
使这个问题更令人困惑的是,实际上在两种情况下会引发异常,因此我们必须防止这两种情况。
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表达式进行了加分,以允许在不使代码嘈杂的情况下进行变量选择。
在按钮中使用此方法的简单方法:
var table = $('#example1').DataTable();
table.row($(`#yesmediasec-${id}`).closest('tr')).remove( ).draw();
example1 = id表。yesmediasec =行中按钮的ID
用它,一切都会好的
[ii]
为[i]
:-)