Подтвердить что ты не робот

Удаление определенных строк из DataTable

Я хочу удалить некоторые строки из DataTable, но он дает такую ​​ошибку,

Коллекция была изменена; операция перечисления может не выполняться

Я использую для удаления этого кода,

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

Итак, в чем проблема и как ее исправить? Какой метод вы посоветуете?

4b9b3361

Ответ 1

Если вы удаляете элемент из коллекции, эта коллекция была изменена, и вы не можете продолжать перечисление по ней.

Вместо этого используйте цикл For, например:

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

Обратите внимание, что вы выполняете итерацию в обратном порядке, чтобы избежать пропуска строки после удаления текущего индекса.

Ответ 2

Прежде чем все перейдут к победе "Вы не можете удалить строки в перечислении", вам необходимо сначала понять, что DataTables являются транзакционными, и технически не очищать изменения, пока вы не вызовете AcceptChanges()

Если вы видите это исключение при вызове Delete, вы уже находитесь в состоянии данных ожидающих изменений. Например, если вы только что загрузили из базы данных, вызов Delete вызовет исключение, если вы будете внутри цикла foreach.

НО! НО!

Если вы загружаете строки из базы данных и вызываете функцию AcceptChanges(), вы фиксируете все эти ожидающие изменения в DataTable. Теперь вы можете перебирать список строк, вызывающих Delete(), не обращая внимания на мир, потому что он просто отмечает строку для удаления, но не фиксируется, пока вы снова не вызовете AcceptChanges()

Я понимаю, что этот ответ немного устарел, но недавно мне пришлось столкнуться с подобной проблемой, и, надеюсь, это избавит от некоторой боли будущего разработчика, работающего над 10-летним кодом :)


Ps Вот простой пример кода, добавленный Джеффом:

С#

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

Ответ 3

Это работает для меня,

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

Ответ 4

с этим решением:

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

Ответ 5

DataRow[] dtr=dtPerson.select("name=Joe");
foreach(var drow in dtr)
{
   drow.delete();
}
dtperson.AcceptChanges();

Я надеюсь, что это поможет вам

Ответ 6

Или просто преобразуйте в строку DataTable строку списка:

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

Ответ 7

Чтобы удалить целую строку из 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);

Ответ 8

В чем проблема: запрещается удалять элементы из коллекции внутри цикла foreach.

Решение: либо делать это, как писал Видор, либо использовать две петли. В первом проходе над DataTable вы сохраняете (во временном списке) ссылки на строки, которые хотите удалить. Затем во втором проходе над вашим временным списком вы удаляете эти строки.

Ответ 9

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

Ответ 10

Я знаю, что это очень старый вопрос, и у меня есть аналогичная ситуация несколько дней назад.

Проблема в том, что в моей таблице прибл. 10000 строк, поэтому петлевые строки DataTable были очень медленными.

Наконец, я нашел гораздо более быстрое решение, где я делаю копию источника DataTable с желаемыми результатами, очистить исходный текст DataTable и merge от временного DataTable в исходный.

note: вместо поиска 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, он будет генерировать исключение), поэтому вы ничего не делаете с вашей таблицей, он остается неизменным.

Ответ 11

У меня есть набор данных в моем приложении, и я пошел на установку изменений (удаление строки), но 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);                 
    }           
}

Ответ 12

Вы пытаетесь это для получения и удаления столбца идентификатора из таблицы данных

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