Quiero eliminar algunas filas de DataTable, pero da un error como este,
Se modificó la colección; Es posible que la operación de enumeración no se ejecute
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 aconsejas?
c#
delete-row
Namco
fuente
fuente
[ii]
a[i]
, sin embargo :-)DataTable
último, lanzará una excepción. La forma correcta sería llamarRemove()
a la fuenteDataTable
-dtPerson.Rows.Remove(dr)
.Delete()
requiere una llamada aAcceptChanges()
para que la eliminación surta efecto?Antes de que todos se suban al tren de ' No puede eliminar filas en una enumeración ', primero debe darse cuenta de que las tablas de datos son transaccionales y no depurar técnicamente los cambios hasta que llame a AcceptChanges ()
Si está viendo esta excepción mientras llama a Delete , ya se encuentra 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 estuviera dentro de un bucle foreach.
¡PERO! ¡PERO!
Si carga filas de la base de datos y llama a la función ' AcceptChanges () ', confirma todos los cambios pendientes en DataTable. Ahora puede iterar a través de la lista de filas que llaman a Delete () sin ninguna preocupación en el mundo, porque simplemente marca la fila para la eliminación, pero no se confirma hasta que llame nuevamente a AcceptChanges ()
Me doy cuenta de que esta respuesta está un poco anticuada, pero tuve que lidiar con un problema similar recientemente y espero que esto le ahorre algo de dolor a un futuro desarrollador que trabaja en un código de 10 años :)
Ps 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()
fuente
object row_loopVariable in ds.Tables(0).Rows
aDataRow row in ds.Tables(0).Rows
counter++
lugar decounter+= 1
.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 utilizar la tabla de datos después de eliminar la fila, obtendrá un error. Entonces, lo que puede hacer es: reemplazar
dr.Delete();
condtPerson.Rows.Remove(dr);
fuente
Esto funciona para mi
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();
fuente
DataRow[] dtr=dtPerson.select("name=Joe"); foreach(var drow in dtr) { drow.delete(); } dtperson.AcceptChanges();
Espero que te ayude
fuente
drow.Delete();
no es, losdrow.delete();
métodos distinguen entre mayúsculas y minúsculas en .net por ciertoPara eliminar toda la fila de DataTable , haga esto
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);
fuente
O simplemente convierta una colección DataTable Row en una lista:
foreach(DataRow dr in dtPerson.Rows.ToList()) { if(dr["name"].ToString()=="Joe") dr.Delete(); }
fuente
Dónde está el problema: está prohibido eliminar elementos de la colección dentro de un bucle foreach.
Solución: hazlo como escribió Widor o usa dos bucles. En la primera pasada sobre DataTable, solo almacena (en una lista temporal) las referencias a las filas que desea eliminar. Luego, en la segunda pasada sobre su lista temporal, borra esas filas.
fuente
<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(); }
fuente
Sé que esta es una pregunta muy antigua y tengo una situación similar hace unos días.
El problema era que en mi mesa hay aprox. 10000 filas, por lo que hacer un bucle en las
DataTable
filas fue muy lento.Finalmente, encontré una solución mucho más rápida, donde hago una copia de la fuente
DataTable
con los resultados deseados, la fuente claraDataTable
y losmerge
resultados de temporalDataTable
a la fuente uno.nota : en su lugar, busque
Joe
enDataRow
llamadoname
Debe buscar todos los registros que no tengan nombreJoe
(forma de búsqueda poco opuesta)Hay 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 un
c#
código (no estoy seguro de si es correcto porque usé el 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, utilicé
Try/Catch
en caso de que no haya resultado (por ejemplo, si TudtPerson
no contienename
Joe
, arrojará una excepción), por lo que no haces nada con Tu tabla, permanece sin cambios.fuente
Tengo un conjunto de datos en mi aplicación y fui a establecer cambios (eliminar una fila), pero
ds.tabales["TableName"]
es de solo lectura. Entonces encontré esta solución.Es una
C#
aplicación wpf ,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); } }
fuente
Intenta esto para obtener y eliminar la columna de identificación de la tabla de datos
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"); }
fuente
Veo varios fragmentos de la respuesta correcta aquí, pero permítanme reunirlos todos y explicar un par de cosas.
En primer lugar,
AcceptChanges
solo debe usarse para marcar la transacción completa en una tabla como validada y confirmada. Lo que significa que si está utilizando DataTable como una fuente de datos para vincularse a, por ejemplo, un servidor SQL, llamarAcceptChanges
manualmente garantizará que los cambios nunca se guarden en el servidor SQL .Lo que hace que este problema sea más confuso es que en realidad hay dos casos en los que se lanza la excepción y tenemos que evitarlos.
1. Modificar la colección de un IEnumerable
No podemos agregar o eliminar un índice a la colección que se está enumerando porque hacerlo puede afectar la indexación interna del enumerador. Hay dos formas de evitar esto: o haga su propia indexación en un ciclo for, o use una colección separada (que no esté modificada) para la enumeración.
2. Intentar leer una entrada eliminada
Dado que las tablas de datos son colecciones transaccionales , las entradas se pueden marcar para su eliminación, pero aún aparecen en la enumeración. Lo que significa que si solicita una entrada eliminada para la columna
"name"
, arrojará una excepción. Lo que significa que debemos verificar sidr.RowState != DataRowState.Deleted
antes de consultar una columna.Poniendolo todo junto
Podríamos ensuciarnos y hacer todo eso manualmente, o podemos dejar que DataTable haga todo el trabajo por nosotros y hacer que la declaración se parezca más a una llamada SQL haciendo lo siguiente:
string name = "Joe"; foreach(DataRow dr in dtPerson.Select($"name='{name}'")) dr.Delete();
Al llamar a la
Select
función de DataTable , nuestra consulta evita automáticamente las entradas ya eliminadas en DataTable. Y dado que laSelect
función devuelve una matriz de coincidencias, la colección sobre la que estamos enumerando no se modifica cuando llamamosdr.Delete()
. También he condimentado la expresión Seleccionar con interpolación de cadenas para permitir la selección de variables sin hacer que el código sea ruidoso.fuente
la forma más fácil de usar este botón en:
var table = $('#example1').DataTable(); table.row($(`#yesmediasec-${id}`).closest('tr')).remove( ).draw();
ejemplo1 = tabla de identificación. yesmediasec = id del botón en la fila
úsalo y todo estará bien
fuente