簡體   English   中英

從數據表中刪除特定行

[英]Deleting specific rows from 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() 的行列表而無需關心,因為它只是將行標記為刪除,但在您再次調用AcceptChanges()之前不會提交

我意識到這個回復有點過時了,但我最近不得不處理一個類似的問題,希望這可以為未來使用 10 年舊代碼的開發人員節省一些痛苦:)


Ps 這是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()

使用此解決方案:

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 中刪除整行,請執行以下操作

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

或者只是將DataTable Row 集合轉換為列表:

foreach(DataRow dr in dtPerson.Rows.ToList())
{
    if(dr["name"].ToString()=="Joe")
    dr.Delete();
}
<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 ,清除源DataTable並將臨時DataTable結果merge到源DataTable

注意:而是在名為name DataRow搜索Joe您必須搜索所有沒有姓名Joe記錄(有點相反的搜索方式)

有例子( 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

我希望這個更短的解決方案會對某人有所幫助。

c#代碼(不確定它是否正確,因為我使用了在線轉換器 :():

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

當然,如果沒有結果,我使用了Try/Catch (例如,如果您的dtPerson不包含name Joe ,它將拋出異常),因此您對您的表不做任何操作,它保持不變。

問題出在哪里:禁止在 foreach 循環內從集合中刪除項目。

解決方案:要么像 Widor 寫的那樣做,要么使用兩個循環。 在第一次通過 DataTable 時,您只存儲(在臨時列表中)對要刪除的行的引用。 然后在第二次遍歷臨時列表時刪除這些行。

我的應用程序中有一個數據集,我去設置更改(刪除一行),但ds.tabales["TableName"]是只讀的。 然后我找到了這個解決方案。

這是一個 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);                 
    }           
}

您嘗試使用此方法從數據表中獲取和刪除 id 列

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

我在這里看到了正確答案的各種零碎部分,但讓我把它們放在一起並解釋一些事情。

首先, AcceptChanges應該只用於將表上的整個事務標記為已驗證和提交。 這意味着如果您使用 DataTable 作為綁定到 SQL 服務器的數據源,則手動調用AcceptChanges將保證更改永遠不會保存到 SQL 服務器

讓這個問題更令人困惑的是,實際上有兩種情況會拋出異常,我們必須防止這兩種情況。

1.修改一個IEnumerable的集合

我們不能向被枚舉的集合添加或刪除索引,因為這樣做可能會影響枚舉器的內部索引。 有兩種方法可以解決這個問題:要么在 for 循環中進行自己的索引,要么使用單獨的集合(未修改)進行枚舉。

2. 嘗試閱讀已刪除的條目

由於數據表是事務性集合,條目可以被標記為刪除,但仍會出現在枚舉中。 這意味着如果您向已刪除的條目詢問列"name"那么它將引發異常。 這意味着我們必須在查詢列之前檢查是否dr.RowState != DataRowState.Deleted

把這一切放在一起

我們可能會變得混亂並手動完成所有這些工作,或者我們可以讓 DataTable 為我們完成所有工作,並通過執行以下操作使語句看起來更像 SQL 調用:

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

通過調用 DataTable 的Select函數,我們的查詢會自動避免 DataTable 中已刪除的條目。 由於Select函數返回一個匹配數組,因此在調用dr.Delete()時不會修改我們正在枚舉的集合。 我還為 Select 表達式添加了字符串插值,以允許在不使代碼嘈雜的情況下進行變量選擇。

在按鈕中使用它的簡單方法:

 var table = $('#example1').DataTable();
 table.row($(`#yesmediasec-${id}`).closest('tr')).remove( ).draw();

示例 1 = id 表。 yesmediasec = 行中按鈕的 id

使用它,一切都會好的

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM