Eu quero excluir algumas linhas de DataTable, mas dá um erro como este,
A coleção foi modificada; operação de enumeração pode não ser executada
Eu uso para excluir este código,
foreach(DataRow dr in dtPerson.Rows){
if(dr["name"].ToString()=="Joe")
dr.Delete();
}
Então, qual é o problema e como corrigi-lo? Qual método você aconselha?
c#
delete-row
namco
fonte
fonte
[ii]
para[i]
:-)DataTable
último, vai lançar uma exceção. A maneira correta seria ligarRemove()
para a fonteDataTable
-dtPerson.Rows.Remove(dr)
.Delete()
requer uma chamada paraAcceptChanges()
para que a exclusão tenha efeito?Antes de todos entrarem no movimento ' Você não pode excluir linhas em uma Enumeração ', você precisa primeiro perceber que DataTables são transacionais e não limpar as alterações tecnicamente até que você chame AcceptChanges ()
Se você está vendo esta exceção ao chamar Delete , você já está em um estado de dados com alterações pendentes . Por exemplo, se você acabou de carregar do banco de dados, chamar Delete lançaria uma exceção se você estivesse dentro de um loop foreach.
MAS! MAS!
Se você carregar linhas do banco de dados e chamar a função ' AcceptChanges () ', você confirma todas as alterações pendentes na DataTable. Agora você pode iterar através da lista de linhas chamando Delete () sem se importar, porque ela simplesmente marca a linha para exclusão, mas não é confirmada até que você chame de novo AcceptChanges ()
Sei que esta resposta está um pouco desatualizada, mas tive que lidar com um problema semelhante recentemente e espero que isso evite um pouco de dor para um futuro desenvolvedor trabalhando em código de 10 anos :)
PS Aqui está um exemplo de código simples adicionado 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()
fonte
object row_loopVariable in ds.Tables(0).Rows
paraDataRow row in ds.Tables(0).Rows
counter++
vez decounter+= 1
.com esta solução:
for(int i = dtPerson.Rows.Count-1; i >= 0; i--) { DataRow dr = dtPerson.Rows[i]; if (dr["name"] == "Joe") dr.Delete(); }
se você for usar a tabela de dados após excluir a linha, receberá um erro. Então, o que você pode fazer é: substituir
dr.Delete();
pordtPerson.Rows.Remove(dr);
fonte
Isso funciona para mim,
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();
fonte
DataRow[] dtr=dtPerson.select("name=Joe"); foreach(var drow in dtr) { drow.delete(); } dtperson.AcceptChanges();
Espero que te ajude
fonte
drow.Delete();
não é osdrow.delete();
métodos diferenciam maiúsculas de minúsculas em .net btwPara remover a linha inteira de DataTable , faça assim
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);
fonte
Ou apenas converta uma coleção de DataTable Row em uma lista:
foreach(DataRow dr in dtPerson.Rows.ToList()) { if(dr["name"].ToString()=="Joe") dr.Delete(); }
fonte
Onde está o problema: É proibido excluir itens da coleção dentro de um loop foreach.
Solução: Faça como Widor escreveu ou use dois loops. Na primeira passagem pelo DataTable, você só armazena (em uma lista temporária) as referências às linhas que deseja excluir. Então, na segunda passagem pela sua lista temporária, você exclui essas linhas.
fonte
<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(); }
fonte
Eu sei que esta é uma pergunta muito antiga, e eu tenho uma situação semelhante há alguns dias.
O problema era que na minha mesa são aprox. 10.000 linhas, então o loop de
DataTable
linhas de calha era muito lento.Finalmente, encontrei uma solução muito mais rápida, onde faço uma cópia da fonte
DataTable
com os resultados desejados, fonte claraDataTable
emerge
resultados do temporárioDataTable
para a fonte um.observação : em vez disso, pesquise
Joe
emDataRow
chamado.name
Você deve pesquisar todos os registros que não tenham nomeJoe
(forma oposta de pesquisa)Há um exemplo (
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 solução mais curta ajude alguém.
Há um
c#
código (não tenho certeza se está correto porque usei um conversor online :()://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;
Claro, eu usei
Try/Catch
no caso se não houver resultado (por exemplo, se SeudtPerson
não contivername
Joe
irá lançar uma exceção), então você não faz nada com Sua tabela, ela permanece inalterada.fonte
Tenho um conjunto de dados em meu aplicativo e fui definir alterações (excluir uma linha) para ele, mas
ds.tabales["TableName"]
é somente leitura. Então eu encontrei essa solução.É um
C#
aplicativo 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); } }
fonte
Você tenta obter e remover a coluna id da tabela de dados
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"); }
fonte
Estou vendo vários pedaços da resposta certa aqui, mas deixe-me juntar tudo e explicar algumas coisas.
Em primeiro lugar,
AcceptChanges
deve ser usado apenas para marcar a transação inteira em uma tabela como sendo validada e confirmada. O que significa que se você estiver usando o DataTable como um DataSource para vinculação a, por exemplo, um servidor SQL, chamarAcceptChanges
manualmente garantirá que as alterações nunca serão salvas no servidor SQL .O que torna esse problema mais confuso é que, na verdade, há dois casos em que a exceção é lançada e temos que evitar os dois.
1. Modificando a coleção de um IEnumerable
Não podemos adicionar ou remover um índice da coleção que está sendo enumerada porque isso pode afetar a indexação interna do enumerador. Há duas maneiras de contornar isso: faça sua própria indexação em um loop for ou use uma coleção separada (que não seja modificada) para a enumeração.
2. Tentativa de ler uma entrada excluída
Como DataTables são coleções transacionais , as entradas podem ser marcadas para exclusão, mas ainda aparecem na enumeração. O que significa que, se você solicitar uma entrada deletada para a coluna
"name"
, será lançada uma exceção. O que significa que devemos verificar sedr.RowState != DataRowState.Deleted
antes de consultar uma coluna.Juntando tudo
Podemos bagunçar e fazer tudo isso manualmente, ou podemos deixar o DataTable fazer todo o trabalho para nós e tornar a instrução mais parecida com uma chamada SQL, fazendo o seguinte:
string name = "Joe"; foreach(DataRow dr in dtPerson.Select($"name='{name}'")) dr.Delete();
Ao chamar a
Select
função de DataTable , nossa consulta evita automaticamente entradas já deletadas na DataTable. E como aSelect
função retorna um array de correspondências, a coleção que estamos enumerando não é modificada quando a chamamosdr.Delete()
. Também apurei a expressão Select com interpolação de string para permitir a seleção de variáveis sem tornar o código barulhento.fonte
a maneira fácil de usar isso no botão:
var table = $('#example1').DataTable(); table.row($(`#yesmediasec-${id}`).closest('tr')).remove( ).draw();
exemplo1 = tabela de id. yesmediasec = id do botão na linha
use e tudo ficará bem
fonte