Suppression de lignes spécifiques de DataTable

Je veux supprimer des lignes de DataTable, mais cela donne une erreur comme celle-ci,

La collection a été modifiée; l’opération d’énumération peut ne pas s’exécuter

J’utilise pour supprimer ce code,

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

Alors, quel est le problème et comment y remédier? Quelle méthode conseillez-vous?

Si vous supprimez un élément d’une collection, cette collection a été modifiée et vous ne pouvez pas continuer à l’énumérer.

Au lieu de cela, utilisez une boucle For, telle que:

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

Notez que vous effectuez une itération en sens inverse pour éviter de sauter une ligne après avoir supprimé l’index actuel.

Avant que tout le monde ne saute sur le mouvement « Vous ne pouvez pas supprimer les lignes dans une énumération », vous devez d’abord vous rendre compte que DataTables est transactionnel et ne pas purger techniquement les modifications tant que vous n’appelez pas AcceptChanges ().

Si vous voyez cette exception lors de l’appel de Delete , vous êtes déjà dans un état de données en attente de modification . Par exemple, si vous venez de charger depuis la firebase database, l’appel de Delete lève une exception si vous vous trouviez dans une boucle foreach.

MAIS! MAIS!

Si vous chargez des lignes depuis la firebase database et appelez la fonction ‘ AcceptChanges () ‘, vous validez toutes les modifications en attente dans le DataTable. Maintenant, vous pouvez parcourir la liste des lignes en appelant Delete () sans avoir à vous soucier du monde, car il marque simplement la ligne pour la suppression, mais n’est pas validée tant que vous n’appelez plus AcceptChanges ().

Je me rends compte que cette réponse est un peu datée, mais j’ai dû faire face à un problème similaire récemment et j’espère que cela permettra d’économiser de la peine pour un futur développeur travaillant sur un code vieux de 10 ans 🙂


Ps Voici un exemple de code simple ajouté par 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() 

avec cette solution:

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

Si vous comptez utiliser le datatable après avoir supprimé la ligne, vous obtiendrez une erreur. Donc, ce que vous pouvez faire est de: remplacer dr.Delete(); avec dtPerson.Rows.Remove(dr);

Cela fonctionne pour moi,

 List lstRemoveColumns = new List() { "ColValue1", "ColVal2", "ColValue3", "ColValue4" }; List rowsToDelete = new List(); foreach (DataRow row in dt.Rows) { if (lstRemoveColumns.Contains(row["ColumnName"].ToSsortingng())) { 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(); 

J’espère que cela vous aidera

Ou simplement convertir une collection de lignes DataTable en une liste:

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

Pour supprimer une ligne entière de DataTable , faites comme ceci

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

Où est le problème: Il est interdit de supprimer des éléments de la collection dans une boucle foreach.

Solution: Faites-le comme l’a écrit Widor ou utilisez deux boucles. Lors du premier passage sur DataTable, vous ne stockez (dans une liste temporaire) que les références aux lignes que vous souhaitez supprimer. Ensuite, dans la seconde passe sur votre liste temporaire, vous supprimez ces lignes.

     <%# Container.DataItemIndex + 1 %>          **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.ToSsortingng()) - 1; DataRow dr = dt.Rows[RowNum]; dr.Delete(); } grd_item_list.DataSource = dt; grd_item_list.DataBind(); } 

Je sais que c’est une très vieille question et j’ai une situation similaire il y a quelques jours.

Le problème était que dans ma table il y a environ 10000 lignes, donc la mise en boucle des lignes DataTable était très lente.

Enfin, j’ai trouvé une solution beaucoup plus rapide, où je fais une copie du source DataTable avec les résultats souhaités, DataTable source DataTable et merge résultats de DataTable temporaire en source.

Remarque : recherchez plutôt Joe dans DataRow appelé name Vous devez rechercher tous les enregistrements dont le nom n’a pas de nom Joe (méthode de recherche peu opposée).

Il y a un exemple ( 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 

J’espère que cette solution plus courte aidera quelqu’un.

Il y a du code c# (pas sûr que ce soit correct car j’ai utilisé le convertisseur en ligne :():

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

Bien sûr, j’ai utilisé Try/Catch au cas où il n’y aurait pas de résultat (par exemple, si votre dtPerson ne contenait pas le name Joe il dtPerson exception), donc vous ne faites rien avec votre table, elle rest inchangée.

J’ai un jeu de données dans mon application et je suis allé y définir des modifications (en supprimant une ligne), mais ds.tabales["TableName"] est en lecture seule. Puis j’ai trouvé cette solution.

C’est une application wpf C# ,

 try { var results = from row in ds.Tables["TableName"].AsEnumerable() where row.Field("Personalid") == "47" select row; foreach (DataRow row in results) { ds.Tables["TableName"].Rows.Remove(row); } }