Удаление определенных строк из DataTable
Я хочу удалить некоторые строки из DataTable, но это дает такую ошибку,
коллекция была изменена; операция перечисления может не выполняться
Я использую для удаления этого кода
foreach(DataRow dr in dtPerson.Rows){
if(dr["name"].ToString()=="Joe")
dr.Delete();
}
Итак, в чем же проблема и как ее решить? Какой метод вы посоветуете?
11 ответов:
Если удалить элемент из коллекции, эта коллекция была изменена и вы не можете продолжать перечислять он.
вместо этого используйте цикл For, например:
for(int i = dtPerson.Rows.Count-1; i >= 0; i--) { DataRow dr = dtPerson.Rows[i]; if (dr["name"] == "Joe") dr.Delete(); }обратите внимание, что вы повторяете в обратном порядке, чтобы избежать пропуска строки после удаления текущего индекса.
прежде чем все прыгают на 'вы не можете удалить строки в перечислении' bandwagon, вы должны сначала понять, что DataTables являются транзакционные, и технически не очищайте изменения, пока вы не позвоните AcceptChanges ()
Если вы видите это исключение при вызове удалить, вы уже в состоянии ожидания-изменения данных. Например, если вы только что загрузились из базы данных, вызов Delete вызовет исключение, если вы находитесь внутри цикла foreach.
но! Но!
Если вы загружаете строки из базы данных и вызываете функцию' AcceptChanges () ' вы фиксируете все эти ожидающие изменения в DataTable. Теперь вы можете перебирать список строк, вызывающих Delete () без заботы в мире, потому что он просто помечает строку для удаления, но не фиксируется до тех пор, пока вы снова звоните AcceptChanges ()
Я понимаю, что этот ответ немного устарел, но недавно мне пришлось иметь дело с подобной проблемой, и, надеюсь, это сэкономит некоторую боль для будущего разработчика, работающего над 10-летним кодом :)
P. s. Вот простой пример кода, добавленный Джефф:
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(); }Если вы собираетесь использовать datatable после удаления строки, вы получите сообщение об ошибке. Так что вы можете сделать, это: заменить
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коллекция строку список:
foreach(DataRow dr in dtPerson.Rows.ToList()) { if(dr["name"].ToString()=="Joe") dr.Delete(); }
удалить строку С 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);
где проблема: запрещено удалять элементы из коллекции внутри цикла foreach.
решение: либо сделайте это, как написал Видор, либо используйте две петли. При первом переходе через 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(); }
я знаю, что это очень старый вопрос, и у меня аналогичная ситуация несколько дней назад.
проблема была в моей таблице приблизительно. 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не содержитnameJoeэто бросит исключение), поэтому вы ничего не делаете с вашей таблицей, она остается неизменной.
у меня есть набор данных в мое приложение, и я пошел, чтобы установить изменения (удаление строки), но
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); } }
Comments