일괄 삭제(C#)Batch Deleting (C#)

Scott Mitchellby Scott Mitchell

코드 다운로드 또는 PDF 다운로드Download Code or Download PDF

단일 작업에서 여러 데이터베이스 레코드를 삭제 하는 방법에 대해 알아봅니다.Learn how to delete multiple database records in a single operation. 사용자 인터페이스 계층에서는 이전 자습서에서 만든 향상 된 GridView를 기반으로 작성 되었습니다.In the User Interface Layer we build upon an enhanced GridView created in an earlier tutorial. 데이터 액세스 계층에서는 트랜잭션 내에서 여러 개의 삭제 작업을 래핑하여 모든 삭제가 성공 하거나 모든 삭제가 롤백되기를 확인 합니다.In the Data Access Layer we wrap the multiple Delete operations within a transaction to ensure that all deletions succeed or all deletions are rolled back.

소개Introduction

이전 자습서 에서는 완전히 편집 가능한 GridView를 사용 하 여 일괄 처리 편집 인터페이스를 만드는 방법을 살펴보았습니다.The preceding tutorial explored how to create a batch editing interface using a fully-editable GridView. 사용자가 일반적으로 한 번에 많은 레코드를 편집 하는 경우에는 일괄 처리 편집 인터페이스에서 훨씬 더 많은 포스트백 및 키보드-마우스 컨텍스트 전환이 필요 하므로 최종 사용자의 효율성을 향상 시킬 수 있습니다.In situations where users are commonly editing many records at once, a batch editing interface will require far fewer postbacks and keyboard-to-mouse context switches, thereby improving the end user s efficiency. 이 기술은 사용자가 한 번의 이동에서 많은 레코드를 삭제 하는 것이 일반적 인 페이지에도 유용 합니다.This technique is similarly useful for pages where it is common for users to delete many records in one go.

온라인 전자 메일 클라이언트를 사용 하는 모든 사용자는 이미 가장 일반적인 배치 삭제 인터페이스 중 하나를 사용 하는 것이 이미 익숙할 것입니다. 즉, 선택한 모든 항목을 삭제 하는 표의 각 행에 있는 확인란을 선택 합니다 (그림 1 참조).Anyone who has used an online email client is already familiar with one of the most common batch deleting interfaces: a checkbox in each row in a grid with a corresponding Delete All Checked Items button (see Figure 1). 이 자습서에서는 웹 기반 인터페이스와 일련의 레코드를 단일 원자성 작업으로 삭제 하는 메서드를 모두 만드는 이전 자습서의 모든 하드 작업을 이미 수행 했기 때문에 더 간단 합니다.This tutorial is rather short because we ve already done all of the hard work in previous tutorials in creating both the web-based interface and a method to delete a series of records as a single atomic operation. 확인란의 Gridview 열 추가 자습서에서는 확인란의 열을 사용 하 여 gridview를 만들고 트랜잭션 내에서 데이터베이스 수정 내용 래핑 자습서에서 트랜잭션을 사용 하 여 ProductID 값의 List<T>를 삭제 하는 메서드를 생성 했습니다.In the Adding a GridView Column of Checkboxes tutorial we created a GridView with a column of checkboxes and in the Wrapping Database Modifications within a Transaction tutorial we created a method in the BLL that would use a transaction to delete a List<T> of ProductID values. 이 자습서에서는 이전 환경을 빌드하고 병합 하 여 작업 일괄 삭제 예제를 만듭니다.In this tutorial, we will build upon and merge our previous experiences to create a working batch deleting example.

각 행 확인란을 포함 합니다.Each Row Includes a Checkbox

그림 1: 각 행에는 확인란 (전체 크기 이미지를 보려면 클릭)이 포함 되어 있습니다.Figure 1: Each Row Includes a Checkbox (Click to view full-size image)

1 단계: 일괄 삭제 인터페이스 만들기Step 1: Creating the Batch Deleting Interface

확인란의 GridView 열 추가 자습서에서 일괄 삭제 인터페이스를 이미 만들었기 때문에 처음부터 새로 만드는 대신 BatchDelete.aspx으로 복사할 수 있습니다.Since we already created the batch deleting interface in the Adding a GridView Column of Checkboxes tutorial, we can simply copy it to BatchDelete.aspx rather than creating it from scratch. 먼저 BatchData 폴더의 BatchDelete.aspx 페이지와 EnhancedGridView 폴더의 CheckBoxField.aspx 페이지를 엽니다.Start by opening the BatchDelete.aspx page in the BatchData folder and the CheckBoxField.aspx page in the EnhancedGridView folder. CheckBoxField.aspx 페이지에서 원본 뷰로 이동 하 고 그림 2와 같이 <asp:Content> 태그 사이에 태그를 복사 합니다.From the CheckBoxField.aspx page, go to the Source view and copy the markup between the <asp:Content> tags as shown in Figure 2.

CheckBoxField의 선언적 태그를 클립보드에 복사 Copy the Declarative Markup of CheckBoxField.aspx to the Clipboard

그림 2: CheckBoxField.aspx의 선언적 태그를 클립보드로 복사 (전체 크기 이미지를 보려면 클릭)Figure 2: Copy the Declarative Markup of CheckBoxField.aspx to the Clipboard (Click to view full-size image)

그런 다음 BatchDelete.aspx의 원본 뷰로 이동 하 여 클립보드의 내용을 <asp:Content> 태그 안에 붙여넣습니다.Next, go to the Source view in BatchDelete.aspx and paste the contents of the clipboard within the <asp:Content> tags. 또한 CheckBoxField.aspx.cs의 코드 숨김이 클래스 내에서 코드를 복사 하 여 BatchDelete.aspx.cs (DeleteSelectedProducts 단추 s Click 이벤트 처리기, ToggleCheckState 메서드 및 ClickCheckAll 단추에 대 한 UncheckAll 이벤트 처리기)에 붙여 넣습니다.Also copy and paste the code from within the code-behind class in CheckBoxField.aspx.cs to within the code-behind class in BatchDelete.aspx.cs (the DeleteSelectedProducts Button s Click event handler, the ToggleCheckState method, and the Click event handlers for the CheckAll and UncheckAll Buttons). 이 콘텐츠를 복사 하 고 나면 BatchDelete.aspx 페이지의 코드 숨김이 클래스에 다음 코드가 포함 되어야 합니다.After copying over this content, the BatchDelete.aspx page s code-behind class should contain the following code:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class BatchData_BatchDelete : System.Web.UI.Page
{
    protected void DeleteSelectedProducts_Click(object sender, EventArgs e)
    {
        bool atLeastOneRowDeleted = false;
        // Iterate through the Products.Rows property
        foreach (GridViewRow row in Products.Rows)
        {
            // Access the CheckBox
            CheckBox cb = (CheckBox)row.FindControl("ProductSelector");
            if (cb != null && cb.Checked)
            {
                // Delete row! (Well, not really...)
                atLeastOneRowDeleted = true;
                // First, get the ProductID for the selected row
                int productID = Convert.ToInt32(Products.DataKeys[row.RowIndex].Value);
                // "Delete" the row
                DeleteResults.Text += string.Format
                    ("This would have deleted ProductID {0}<br />", productID);
                //... To actually delete the product, use ...
                //ProductsBLL productAPI = new ProductsBLL();
                //productAPI.DeleteProduct(productID);
                //............................................
            }
        }
        // Show the Label if at least one row was deleted...
        DeleteResults.Visible = atLeastOneRowDeleted;
    }
    private void ToggleCheckState(bool checkState)
    {
        // Iterate through the Products.Rows property
        foreach (GridViewRow row in Products.Rows)
        {
            // Access the CheckBox
            CheckBox cb = (CheckBox)row.FindControl("ProductSelector");
            if (cb != null)
                cb.Checked = checkState;
        }
    }
    protected void CheckAll_Click(object sender, EventArgs e)
    {
        ToggleCheckState(true);
    }
    protected void UncheckAll_Click(object sender, EventArgs e)
    {
        ToggleCheckState(false);
    }
}

선언적 태그 및 소스 코드를 복사 하 고 나 서 브라우저를 통해 확인 하 여 BatchDelete.aspx 테스트 합니다.After copying over the declarative markup and source code, take a moment to test BatchDelete.aspx by viewing it through a browser. GridView에서 처음 10 개 제품을 나열 하는 GridView가 표시 되어야 합니다. 각 행에는 제품 이름, 범주 및 가격이 나열 됩니다 (확인란 포함).You should see a GridView listing the first ten products in a GridView with each row listing the product s name, category, and price along with a checkbox. 선택한 제품을 모두 선택 하 고 모두 선택 취소 하 고 삭제 하는 세 가지 단추가 있습니다.There should be three buttons: Check All, Uncheck All, and Delete Selected Products. 모두 확인 단추를 클릭 하면 모든 확인란을 선택 하 고 모두 선택 취소는 모든 확인란의 선택을 취소 합니다.Clicking the Check All button selects all checkboxes, while Uncheck All clears all checkboxes. 선택한 제품 삭제를 클릭 하면 선택한 제품의 ProductID 값을 나열 하지만 실제로는 제품이 삭제 되지 않는다는 메시지가 표시 됩니다.Clicking Delete Selected Products displays a message that lists the ProductID values of the selected products, but does not actually delete the products.

CheckBoxField의 인터페이스가 BatchDeleting로 이동 되었습니다. The Interface from CheckBoxField.aspx has been Moved to BatchDeleting.aspx

그림 3: CheckBoxField.aspx의 인터페이스가 BatchDeleting.aspx으로 이동 되었습니다 (전체 크기 이미지를 보려면 클릭).Figure 3: The Interface from CheckBoxField.aspx has been Moved to BatchDeleting.aspx (Click to view full-size image)

2 단계: 트랜잭션을 사용 하 여 선택 된 제품 삭제Step 2: Deleting the Checked Products Using Transactions

일괄 처리 삭제 인터페이스가 BatchDeleting.aspx에 성공적으로 복사 되 면 선택한 제품 삭제 단추가 ProductsBLL 클래스의 DeleteProductsWithTransaction 메서드를 사용 하 여 선택 된 제품을 삭제 하도록 코드를 업데이트 하는 것만 남았습니다.With the batch deleting interface successfully copied over to BatchDeleting.aspx, all that remains is to update the code so that the Delete Selected Products button deletes the checked products using the DeleteProductsWithTransaction method in the ProductsBLL class. 트랜잭션 자습서에서 데이터베이스 수정 내용 래핑 에 추가 된이 메서드는 ProductID 값의 List<T> 입력으로 받아들이고 트랜잭션 범위 내에서 해당 하는 각 ProductID를 삭제 합니다.This method, added in the Wrapping Database Modifications within a Transaction tutorial, accepts as its input a List<T> of ProductID values and deletes each corresponding ProductID within the scope of a transaction.

DeleteSelectedProducts Button s Click 이벤트 처리기는 현재 다음 foreach 루프를 사용 하 여 각 GridView 행을 반복 합니다.The DeleteSelectedProducts Button s Click event handler currently uses the following foreach loop to iterate through each GridView row:

// Iterate through the Products.Rows property
foreach (GridViewRow row in Products.Rows)
{
    // Access the CheckBox
    CheckBox cb = (CheckBox)row.FindControl("ProductSelector");
    if (cb != null && cb.Checked)
    {
        // Delete row! (Well, not really...)
        atLeastOneRowDeleted = true;
        // First, get the ProductID for the selected row
        int productID = Convert.ToInt32(Products.DataKeys[row.RowIndex].Value);
        // "Delete" the row
        DeleteResults.Text += string.Format
            ("This would have deleted ProductID {0}<br />", productID);
        //... To actually delete the product, use ...
        //ProductsBLL productAPI = new ProductsBLL();
        //productAPI.DeleteProduct(productID);
        //............................................
    }
}

ProductSelector CheckBox 웹 컨트롤은 각 행에 대해 프로그래밍 방식으로 참조 됩니다.For each row, the ProductSelector CheckBox Web control is programmatically referenced. 이 확인란이 선택 되어 있으면 행 ProductID DataKeys 컬렉션에서 검색 되 고 DeleteResults 레이블 s Text 속성은 행을 삭제 하도록 선택 했음을 나타내는 메시지를 포함 하도록 업데이트 됩니다.If it is checked, the row s ProductID is retrieved from the DataKeys collection and the DeleteResults Label s Text property is updated to include a message indicating that the row was selected for deletion.

위의 코드는 ProductsBLL 클래스 Delete 메서드에 대 한 호출이 주석 처리 됨에 따라 실제로 레코드를 삭제 하지 않습니다. 이 삭제 논리가 적용 되었으므로 코드에서 제품이 삭제 되지만 원자성 작업 내에서는 삭제 되지 않습니다.The above code does not actually delete any records as the call to the ProductsBLL class s Delete method is commented out. Were this delete logic to be applied, the code would delete the products but not within an atomic operation. 즉, 시퀀스에서 처음 몇 개의 삭제가 성공 했지만 나중에 실패 한 경우 (foreign key 제약 조건 위반으로 인해) 예외가 throw 되지만 이미 삭제 된 제품은 삭제 된 상태로 유지 됩니다.That is, if the first few deletes in the sequence succeeded, but a later one failed (perhaps due to a foreign key constraint violation), an exception would be thrown but those products already deleted would remain deleted.

원자성을 보장 하기 위해 ProductsBLL 클래스 s DeleteProductsWithTransaction 메서드를 대신 사용 해야 합니다.In order to assure atomicity, we need to instead use the ProductsBLL class s DeleteProductsWithTransaction method. 이 메서드는 ProductID 값 목록을 허용 하므로 먼저 표에서이 목록을 컴파일한 다음 매개 변수로 전달 해야 합니다.Because this method accepts a list of ProductID values, we need to first compile this list from the grid and then pass it as a parameter. 먼저 int형식의 List<T> 인스턴스를 만듭니다.We first create an instance of a List<T> of type int. foreach 루프 내에서 선택한 products ProductID 값을이 List<T>에 추가 해야 합니다.Within the foreach loop we need to add the selected products ProductID values to this List<T>. 루프 후이 List<T> ProductsBLL 클래스 DeleteProductsWithTransaction 메서드에 전달 해야 합니다.After the loop this List<T> must be passed to the ProductsBLL class s DeleteProductsWithTransaction method. 다음 코드를 사용 하 여 DeleteSelectedProducts Button s Click 이벤트 처리기를 업데이트 합니다.Update the DeleteSelectedProducts Button s Click event handler with the following code:

protected void DeleteSelectedProducts_Click(object sender, EventArgs e)
{
    // Create a List to hold the ProductID values to delete
    System.Collections.Generic.List<int> productIDsToDelete = 
        new System.Collections.Generic.List<int>();
    // Iterate through the Products.Rows property
    foreach (GridViewRow row in Products.Rows)
    {
        // Access the CheckBox
        CheckBox cb = (CheckBox)row.FindControl("ProductSelector");
        if (cb != null && cb.Checked)
        {
            // Save the ProductID value for deletion
            // First, get the ProductID for the selected row
            int productID = Convert.ToInt32(Products.DataKeys[row.RowIndex].Value);
            // Add it to the List...
            productIDsToDelete.Add(productID);
            // Add a confirmation message
            DeleteResults.Text += string.Format
                ("ProductID {0} has been deleted<br />", productID);
        }
    }
    // Call the DeleteProductsWithTransaction method and show the Label 
    // if at least one row was deleted...
    if (productIDsToDelete.Count > 0)
    {
        ProductsBLL productAPI = new ProductsBLL();
        productAPI.DeleteProductsWithTransaction(productIDsToDelete);
        DeleteResults.Visible = true;
        // Rebind the data to the GridView
        Products.DataBind();
    }
}

업데이트 된 코드는 int (productIDsToDelete) 형식의 List<T>를 만들고 삭제할 ProductID 값으로 채웁니다.The updated code creates a List<T> of type int (productIDsToDelete) and populates it with the ProductID values to delete. foreach 루프 후 하나 이상의 제품이 선택 되어 있으면 ProductsBLL 클래스 s DeleteProductsWithTransaction 메서드가 호출 되 고이 목록을 전달 합니다.After the foreach loop, if there is at least one product selected, the ProductsBLL class s DeleteProductsWithTransaction method is called and passed this list. DeleteResults 레이블만 표시 되 고 데이터를 GridView로 데이터 바인딩 (새로 삭제 된 레코드가 더 이상 표에 행으로 표시 되지 않음).The DeleteResults Label is also displayed and the data rebound to the GridView (so that the newly-deleted records no longer appear as rows in the grid).

그림 4는 삭제를 위해 여러 행이 선택 된 후의 GridView를 보여 줍니다.Figure 4 shows the GridView after a number of rows have been selected for deletion. 그림 5는 선택한 제품 삭제 단추를 클릭 한 직후의 화면을 보여 줍니다.Figure 5 shows the screen immediately after the Delete Selected Products button has been clicked. 그림 5에서 삭제 된 레코드의 ProductID 값은 GridView 아래 레이블에 표시 되 고 해당 행은 더 이상 GridView에 표시 되지 않습니다.Note that in Figure 5 the ProductID values of the deleted records are displayed in the Label beneath the GridView and those rows are no longer in the GridView.

선택한 제품을 삭제 The Selected Products Will Be Deleted

그림 4: 선택한 제품이 삭제 됩니다 (전체 크기 이미지를 보려면 클릭).Figure 4: The Selected Products Will Be Deleted (Click to view full-size image)

삭제 된 Products ProductID 값 GridView 아래에 나열 됩니다.The Deleted Products ProductID Values are Listed Beneath the GridView

그림 5: 삭제 된 Products ProductID 값은 GridView 아래에 나열 됩니다 (전체 크기 이미지를 보려면 클릭).Figure 5: The Deleted Products ProductID Values are Listed Beneath the GridView (Click to view full-size image)

Note

DeleteProductsWithTransaction 메서드 원자성을 테스트 하려면 Order Details 테이블에서 제품에 대 한 항목을 수동으로 추가한 다음 해당 제품 (다른 사용자와 함께)을 삭제 하려고 시도 합니다.To test the DeleteProductsWithTransaction method s atomicity, manually add an entry for a product in the Order Details table and then attempt to delete that product (along with others). 연결 된 순서를 사용 하 여 제품을 삭제 하려고 하면 foreign key 제약 조건 위반이 발생 하지만, 선택한 다른 제품 삭제가 롤백되는 것을 확인할 수 있습니다.You will receive a foreign key constraint violation when attempting to delete the product with an associated order, but note how the other selected products deletions are rolled back.

요약Summary

일괄 삭제 인터페이스를 만들려면 확인란의 열과 함께 GridView를 추가 하 고 클릭 하면 선택한 모든 행을 단일 원자성 작업으로 삭제 하는 단추 웹 컨트롤이 포함 됩니다.Creating a batch deleting interface involves adding a GridView with a column of checkboxes and a Button Web control that, when clicked, will delete all of the selected rows as a single atomic operation. 이 자습서에서는 두 가지 이전 자습서에서 작업을 함께 수행 하 고, 확인란의 GridView 열을 추가 하 고, 트랜잭션 내에서 데이터베이스 수정 내용을 래핑하는 방법으로 piecing 하 여 이러한 인터페이스를 구축 했습니다.In this tutorial we built such an interface by piecing together work done in two previous tutorials, Adding a GridView Column of Checkboxes and Wrapping Database Modifications within a Transaction. 첫 번째 자습서에서는 확인란 및 열이 포함 된 GridView를 만들었으며 후자에서 메서드를 구현 했습니다 .이 메서드는 ProductIDList<T> 전달 될 때 트랜잭션 범위 내에서 모두 삭제 되었습니다.In the first tutorial we created a GridView with a column of checkboxes and in the latter we implemented a method in the BLL that, when passed a List<T> of ProductID values, deleted them all within the scope of a transaction.

다음 자습서에서는 배치 삽입을 수행 하는 인터페이스를 만듭니다.In the next tutorial we'll create an interface for performing batch inserts.

행복 한 프로그래밍Happy Programming!

저자 정보About the Author

Scott Mitchell(7 개의 ASP/ASP. NET books 및 4GuysFromRolla.com창립자)은 1998부터 Microsoft 웹 기술을 사용 하 여 작업 했습니다.Scott Mitchell, author of seven ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Scott은 독립 컨설턴트, 강사 및 기록기로 작동 합니다.Scott works as an independent consultant, trainer, and writer. 최신 책은 24 시간 이내에 ASP.NET 2.0을 sams teach yourself것입니다.His latest book is Sams Teach Yourself ASP.NET 2.0 in 24 Hours. mitchell@4GuysFromRolla.com에 도달할 수 있습니다 .He can be reached at mitchell@4GuysFromRolla.com. 또는 블로그를 통해 http://ScottOnWriting.NET에서 찾을 수 있습니다.or via his blog, which can be found at http://ScottOnWriting.NET.

특별히 감사 합니다.Special Thanks To

이 자습서 시리즈는 많은 유용한 검토자가 검토 했습니다.This tutorial series was reviewed by many helpful reviewers. 이 자습서의 리드 검토자는 Hilton Gid Esenow 및 Teresa Murphy 였습니다.Lead reviewers for this tutorial were Hilton Giesenow and Teresa Murphy. 예정 된 MSDN 문서를 검토 하는 데 관심이 있나요?Interested in reviewing my upcoming MSDN articles? 그렇다면mitchell@4GuysFromRolla.com에서 줄을 삭제 합니다.If so, drop me a line at mitchell@4GuysFromRolla.com.