从DataTable中删除特定的行
本文关键字:删除 DataTable | 更新日期: 2023-09-27 17:50:09
我想从DataTable中删除一些行,但它给出了这样的错误,
Collection被修改;枚举操作可能无法执行
我用来删除这段代码,
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();
请注意,您是反向迭代,以避免在删除当前索引后跳过一行。
在每个人都跳上'枚举'潮流中不能删除行之前,您需要首先认识到数据表是事务性的,并且在调用AcceptChanges()之前不会从技术上清除更改,直到您调用AcceptChanges()
如果在调用Delete时看到此异常,则已经处于pending-changes data state。例如,如果您刚刚从数据库加载,如果您在foreach循环中,调用Delete将抛出异常。
但是!但是!
如果你从数据库中加载行并调用函数'AcceptChanges()',你将所有这些挂起的更改提交到DataTable。现在您可以遍历调用Delete()的行列表,而不必担心,因为它只是将行标记为Delete,但直到您再次调用AcceptChanges()
才会提交。我意识到这个回答有点过时了,但我最近不得不处理一个类似的问题,希望这能为未来的开发人员在10年前的代码上工作节省一些痛苦:)
注。下面是Jeff添加的一个简单的代码示例:
c#YourDataTable.AcceptChanges();
foreach (DataRow row in YourDataTable.Rows) {
// If this row is offensive then
row.Delete();
}
YourDataTable.AcceptChanges();
VB。
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"); //name is the column in the data table
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行集合转换为列表:
foreach(DataRow dr in dtPerson.Rows.ToList())
{
if(dr["name"].ToString()=="Joe")
dr.Delete();
}
问题在哪里:禁止在foreach循环中从集合中删除项。
解决方案:要么像Widor写的那样,要么使用两个循环。在第一次传递DataTable时,您只存储(在临时列表中)对要删除的行的引用。然后在第二次遍历临时列表时删除这些行。
<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();
}
我知道这是一个非常古老的问题,几天前我也有类似的情况。
问题是,在我的表是大约。
最后,我找到了更快的解决方案,在那里我复制源DataTable
与期望的结果,从临时DataTable
清除源DataTable
和merge
结果到源1。
注释:在DataRow
中搜索Joe
,而在name
中搜索CC_8,必须搜索所有不名为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
它会抛出异常),所以你对你的表什么也不做,它保持不变。
您可以尝试从数据表
获取和删除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
应该只用于将表上的整个事务标记为验证和提交。这意味着如果您使用数据表作为数据源绑定到,例如SQL服务器,那么手动调用AcceptChanges
将保证更改永远不会保存到SQL服务器。
使这个问题更令人困惑的是,实际上有两种情况抛出异常,我们必须防止这两种情况。
1。修改IEnumerable的Collection
不能为枚举的集合添加或删除索引,因为这样做可能会影响枚举数的内部索引。有两种方法可以解决这个问题:要么在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表达式添加了香料,以允许变量选择而不会使代码嘈杂。
我在我的应用程序中有一个数据集,我去设置更改(删除一行),但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);
}
}
使用这个按钮的简单方法:
var table = $('#example1').DataTable();
table.row($(`#yesmediasec-${id}`).closest('tr')).remove( ).draw();
example1 = id table。Yesmediasec =行中按钮的id
使用它,一切都会好的