Eliminar filas específicas de DataTable


Quiero eliminar algunas filas de DataTable, pero da un error como este,

Se modificó la colección; la operación de enumeración podría no ejecutarse

Uso para borrar este código,

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

Entonces, ¿cuál es el problema y cómo solucionarlo? ¿Qué método aconseja?

Author: Aziz Shaikh, 2011-04-13

11 answers

Si elimina un elemento de una colección, esa colección se ha cambiado y no puede continuar enumerando a través de ella.

En su lugar, use un bucle For, como:

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

Tenga en cuenta que está iterando en sentido inverso para evitar saltar una fila después de eliminar el índice actual.

 118
Author: Widor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-13 11:36:32

Antes de que todos se suban al carro' No puede eliminar filas en una Enumeración', primero debe darse cuenta de que las tablas de datos son transaccional, y no purgue técnicamente los cambios hasta que llame a AcceptChanges()

Si está viendo esta excepción mientras llama a Delete, ya está en un estado de datos de cambios pendientes. Por ejemplo, si acaba de cargar desde la base de datos, llamar a Delete lanzaría una excepción si estaban dentro de un bucle foreach.

PERO! ¡PERO!

Si carga filas desde la base de datos y llama a la función 'AcceptChanges()', confirma todos los cambios pendientes en la DataTable. Ahora puede iterar a través de la lista de filas que llaman a Delete() sin un cuidado en el mundo, porque simplemente marca la fila para la eliminación, pero no se confirma hasta que nuevamente llame AcceptChanges()

Me doy cuenta de que esta respuesta es un poco anticuada, pero tuve que lidiar con un problema similar recientemente y con suerte esto ahorra algo de dolor para un futuro desarrollador que trabaja en código de 10 años:)


P. s. Aquí hay un ejemplo de código simple agregado por 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()
 95
Author: Steve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-14 13:33:23

Con esta solución:

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

Si va a usar la datatable después de eliminar la fila, obtendrá un error. Así que lo que puedes hacer es: sustitúyase dr.Delete(); por dtPerson.Rows.Remove(dr);

 13
Author: bokkie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-05 09:43:36

Esto funciona para mí,

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();
 12
Author: Balaji Birajdar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 06:26:32
DataRow[] dtr=dtPerson.select("name=Joe");
foreach(var drow in dtr)
{
   drow.delete();
}
dtperson.AcceptChanges();

Espero que te ayude

 7
Author: Karthik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-16 13:45:07

O simplemente convertir un DataTable Colección de filas a una lista:

foreach(DataRow dr in dtPerson.Rows.ToList())
{
    if(dr["name"].ToString()=="Joe")
    dr.Delete();
}
 4
Author: Milos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-20 16:50:45

Eliminar toda la fila de DataTable , haz como

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);
 2
Author: Karthikeyan P,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-29 13:53:55

Dónde está el problema: Está prohibido eliminar elementos de la colección dentro de un bucle foreach.

Solución: Hazlo como Widor escribió, o usa dos bucles. En el primer paso sobre DataTable solo almacena (en una lista temporal) las referencias a las filas que desea eliminar. Luego, en el segundo paso sobre su lista temporal, elimina esas filas.

 1
Author: Al Kepp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-13 11:28:33
<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();
}
 1
Author: Arun Prasad E S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-26 15:49:59

Sé que esta es una pregunta muy antigua, y tengo una situación similar hace unos días.

El problema era, en mi tabla son aprox. 10000 filas, por lo que el bucle trough DataTable filas era muy lento.

Finalmente, encontré una solución mucho más rápida, donde hago una copia de source DataTable con los resultados deseados, clear source DataTable y merge resultados de temporary DataTable en source one.

Nota : en lugar de buscar Joe en DataRow llamado name Usted tiene que buscar todos los registros cuya no tienen nombre Joe (forma poco opuesta de búsqueda)

Hay un ejemplo (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

Espero que esta solución más corta ayude a alguien.

Hay c# código (no estoy seguro de que sea correcto porque usé convertidor en línea :( ):

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

Por supuesto, usé Try/Catch en caso de que no haya resultado (por ejemplo, si Su dtPerson no contiene name Joe se lanzará excepción), por lo que no hacer nada con Su mesa, se mantiene sin cambios.

 1
Author: nelek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-15 06:23:03

Tengo un conjunto de datos en mi aplicación y fui a establecer cambios (eliminar una fila) en él, pero ds.tabales["TableName"] es de solo lectura. Entonces encontré esta solución.

Es una aplicación 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);                 
    }           
}
 0
Author: Mamad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 05:55:41