program story

DataTable에서 특정 행 삭제

inputbox 2020. 11. 9. 08:08
반응형

DataTable에서 특정 행 삭제


DataTable에서 일부 행을 삭제하고 싶지만 다음과 같은 오류가 발생합니다.

컬렉션이 수정되었습니다. 열거 작업이 실행되지 않을 수 있음

이 코드를 삭제하는 데 사용합니다.

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

그렇다면 문제는 무엇이며 어떻게 해결합니까? 어떤 방법을 권합니까?


컬렉션에서 항목을 삭제하면 해당 컬렉션이 변경되어 계속 열거 할 수 없습니다.

대신 다음과 같은 For 루프를 사용하십시오.

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

현재 색인을 삭제 한 후 행을 건너 뛰지 않도록 역순으로 반복합니다.


모든 사람이 ' 열거 형에서 행을 삭제할 수 없습니다 '라는 유행에 뛰어 들기 전에 먼저 DataTables가 트랜잭션 적이라는 것을 인식하고 AcceptChanges () 를 호출 할 때까지 기술적으로 변경 사항을 제거하지 않아야합니다.

Delete 를 호출하는 동안이 예외가 표시되는 경우 이미 변경 보류중인 데이터 상태 입니다. 예를 들어, 데이터베이스에서 방금로드 한 경우, foreach 루프 내에있는 경우 Delete를 호출하면 예외가 발생합니다.

그러나! 그러나!

데이터베이스에서 행을로드하고 ' AcceptChanges () ' 함수를 호출하면 보류중인 모든 변경 사항을 DataTable에 커밋합니다. 이제 Delete ()를 호출하는 행 목록을 반복 할 수 있습니다. 단순히 행에 Deletion을 표시하지만 AcceptChanges ()다시 호출 할 때까지 커밋되지 않기 때문입니다.

나는이 응답이 약간 오래된 것임을 알고 있지만 최근에 비슷한 문제를 다루어야했고 이것이 10 년 된 코드를 작업하는 미래의 개발자에게 약간의 고통을 덜어주기를 바랍니다. :)


추신 다음은 Jeff가 추가 한 간단한 코드 예제입니다 .

씨#

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

이 솔루션으로 :

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

행을 삭제 한 후 데이터 테이블을 사용하려는 경우 오류가 발생합니다. 따라서 할 수있는 일은 다음 dr.Delete();같습니다.dtPerson.Rows.Remove(dr);


이것은 나를 위해 작동합니다.

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

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

도움이 되길 바랍니다


또는 DataTable Row 컬렉션 을 목록으로 변환 하십시오.

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

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

문제가있는 곳 : foreach 루프 내의 컬렉션에서 항목을 삭제하는 것은 금지되어 있습니다.

솔루션 : Widor가 작성한 것처럼 수행하거나 두 개의 루프를 사용하십시오. DataTable의 첫 번째 단계에서는 삭제하려는 행에 대한 참조 만 임시 목록에 저장합니다. 그런 다음 임시 목록에 대한 두 번째 단계에서 해당 행을 삭제합니다.


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

나는 이것이 매우 오래된 질문이라는 것을 알고 있으며 며칠 전에 비슷한 상황이 발생했습니다.

문제는 내 테이블에 약입니다. 10000 개의 행이므로 루핑 트로프 DataTable행은 매우 느 렸습니다.

마지막으로 DataTable원하는 결과, 명확한 소스 DataTablemerge임시 결과 DataTable를 소스 1로 복사하는 훨씬 빠른 솔루션을 찾았습니다 .

참고 : 대신 호출 됨을 검색합니다 Joe. 이름이없는 모든 레코드를 검색해야합니다 (검색 과 약간 반대).DataRownameJoe

There is example (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

I hope so this shorter solution will help someone.

There is c# code (not sure is it correct because I used online converter :( ):

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

Of course, I used Try/Catch in case if there is no result (for example, if Your dtPerson don't contain name Joe it will throw exception), so You do nothing with Your table, it stays unchanged.


I have a dataset in my app and I went to set changes (deleting a row) to it but ds.tabales["TableName"] is read only. Then I found this solution.

It's a wpf C# app,

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

You try this for getting and removing id column from data table

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

I'm seeing various bits and pieces of the right answer here, but let me bring it all together and explain a couple of things.

First of all, AcceptChanges should only be used to mark the entire transaction on a table as being validated and committed. Which means if you are using the DataTable as a DataSource for binding to, for example, an SQL server, then calling AcceptChanges manually will guarantee that that the changes never get saved to the SQL server.

What makes this issue more confusing is that there are actually two cases in which the exception is thrown and we have to prevent both of them.

1. Modifying an IEnumerable's Collection

We can't add or remove an index to the collection being enumerated because doing so may affect the enumerator's internal indexing. There are two ways to get around this: either do your own indexing in a for loop, or use a separate collection (that is not modified) for the enumeration.

2. Attempting to Read a Deleted Entry

Since DataTables are transactional collections, entries can be marked for deletion but still appear in the enumeration. Which means that if you ask a deleted entry for the column "name" then it will throw an exception. Which means we must check to see whether dr.RowState != DataRowState.Deleted before querying a column.

Putting it all together

We could get messy and do all of that manually, or we can let the DataTable do all the work for us and make the statement look and at more like an SQL call by doing the following:

string name = "Joe";
foreach(DataRow dr in dtPerson.Select($"name='{name}'"))
    dr.Delete();

By calling DataTable's Select function, our query automatically avoids already deleted entries in the DataTable. And since the Select function returns an array of matches, the collection we are enumerating over is not modified when we call dr.Delete(). I've also spiced up the Select expression with string interpolation to allow for variable selection without making the code noisy.

참고URL : https://stackoverflow.com/questions/5648339/deleting-specific-rows-from-datatable

반응형