다음을 통해 공유


일괄 처리 업데이트 수행(C#)

작성자: 스콧 미첼

PDF 다운로드

페이지에서 "모두 업데이트" 단추를 클릭하여 모든 항목이 편집 모드이고 값을 저장할 수 있는 완전히 편집 가능한 DataList를 만드는 방법을 알아봅니다.

소개

이전 자습서에서는 항목 수준 DataList를 만드는 방법을 검토했습니다. 표준 편집 가능한 GridView와 마찬가지로 DataList의 각 항목에는 항목을 편집할 수 있도록 하는 편집 단추가 포함되어 있습니다. 이 항목 수준 편집은 가끔만 업데이트되는 데이터에 적합하지만 특정 사용 사례 시나리오에서는 사용자가 많은 레코드를 편집해야 합니다. 사용자가 수십 개의 레코드를 편집해야 하고 편집을 클릭하고 변경한 다음 각 레코드에 대한 업데이트를 클릭해야 하는 경우 클릭 양이 생산성을 저해할 수 있습니다. 이러한 경우 모든 항목이 편집 모드에 있고 페이지에서 모두 업데이트 단추를 클릭하여 값을 편집할 수 있는 완전히 편집 가능한 DataList를 제공하는 것이 더 좋습니다(그림 1 참조).

완전히 편집 가능한 DataList의 각 항목을 수정할 수 있습니다.

그림 1: 완전히 편집 가능한 DataList의 각 항목을 수정할 수 있습니다(전체 크기 이미지를 보려면 클릭).

이 자습서에서는 사용자가 완전히 편집 가능한 DataList를 사용하여 공급업체 주소 정보를 업데이트할 수 있도록 하는 방법을 살펴봅니다.

1단계: DataList의 ItemTemplate에서 편집 가능한 사용자 인터페이스 만들기

항목 수준 편집 가능한 표준 DataList를 만드는 이전 자습서에서는 다음 두 가지 템플릿을 사용했습니다.

  • ItemTemplate 에는 읽기 전용 사용자 인터페이스(각 제품의 이름과 가격을 표시하기 위한 레이블 웹 컨트롤)가 포함되어 있습니다.
  • EditItemTemplate 에는 편집 모드 사용자 인터페이스(두 개의 TextBox 웹 컨트롤)가 포함되어 있습니다.

DataList의 EditItemIndex 속성은 .를 사용하여 렌더링되는 항목 DataListItem (있는 경우)을 EditItemTemplate지정합니다. 특히 해당 값이 DataListItemItemIndex DataList의 EditItemIndex 속성과 일치하는 값은 .를 EditItemTemplate사용하여 렌더링됩니다. 이 모델은 한 번에 하나의 항목만 편집할 수 있지만 완전히 편집 가능한 DataList를 만들 때는 무너질 때 잘 작동합니다.

완전히 편집 가능한 DataList의 경우 편집 가능한 인터페이스를 사용하여 모든DataListItem합니다. 이 작업을 수행하는 가장 간단한 방법은 .에서 편집 가능한 인터페이스를 정의하는 것입니다 ItemTemplate. 공급자 주소 정보를 수정하기 위해 편집 가능한 인터페이스는 공급자 이름을 텍스트로 포함하고 주소, 도시 및 국가/지역 값에 대한 TextBoxes를 포함합니다.

먼저 페이지를 열고 BatchUpdate.aspx DataList 컨트롤을 추가하고 해당 ID 속성을 Suppliers.로 설정합니다. DataList의 스마트 태그에서 명명 SuppliersDataSource된 새 ObjectDataSource 컨트롤을 추가하도록 선택합니다.

SuppliersDataSource라는 새 ObjectDataSource 만들기

그림 2: 명명된 SuppliersDataSource 새 ObjectDataSource 만들기(전체 크기 이미지를 보려면 클릭)

클래스 메서드 SuppliersBLL 를 사용하여 데이터를 검색하도록 ObjectDataSource를 GetSuppliers() 구성합니다(그림 3 참조). 이전 자습서와 마찬가지로 ObjectDataSource를 통해 공급자 정보를 업데이트하는 대신 비즈니스 논리 계층으로 직접 작업합니다. 따라서 업데이트 탭에서 드롭다운 목록을 (없음)으로 설정합니다(그림 4 참조).

GetSuppliers() 메서드를 사용하여 공급업체 정보 검색

그림 3: 메서드를 GetSuppliers() 사용하여 공급업체 정보 검색(전체 크기 이미지를 보려면 클릭)

업데이트 탭에서 드롭다운 목록을 (없음)으로 설정

그림 4: 업데이트 탭에서 드롭다운 목록을 (없음)으로 설정합니다(전체 크기 이미지를 보려면 클릭).

마법사를 완료한 후 Visual Studio는 DataList를 ItemTemplate 자동으로 생성하여 레이블 웹 컨트롤의 데이터 원본에서 반환된 각 데이터 필드를 표시합니다. 대신 편집 인터페이스를 제공하려면 이 템플릿을 수정해야 합니다. ItemTemplate DataList의 스마트 태그에서 템플릿 편집 옵션을 사용하거나 선언적 구문을 통해 직접 디자이너를 통해 사용자 지정할 수 있습니다.

잠시 시간을 내어 공급자의 이름을 텍스트로 표시하지만 공급자 주소, 도시 및 국가/지역 값에 대한 TextBoxes를 포함하는 편집 인터페이스를 만듭니다. 이러한 변경을 수행한 후 페이지의 선언적 구문은 다음과 유사하게 표시됩니다.

<asp:DataList ID="Suppliers" runat="server" DataKeyField="SupplierID"
    DataSourceID="SuppliersDataSource">
    <ItemTemplate>
        <h4><asp:Label ID="CompanyNameLabel" runat="server"
            Text='<%# Eval("CompanyName") %>' /></h4>
        <table border="0">
            <tr>
                <td class="SupplierPropertyLabel">Address:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Address" runat="server"
                        Text='<%# Eval("Address") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">City:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="City" runat="server"
                        Text='<%# Eval("City") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">Country:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Country" runat="server"
                        Text='<%# Eval("Country") %>' />
                </td>
            </tr>
        </table>
        <br />
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
</asp:ObjectDataSource>

비고

이전 자습서와 마찬가지로 이 자습서의 DataList는 뷰 상태를 사용하도록 설정해야 합니다.

I에서는 ItemTemplate 두 개의 새 CSS 클래스를 사용하고 있으며SupplierPropertyLabel, SupplierPropertyValue 클래스에 Styles.css 추가되고 CSS 클래스와 ProductPropertyLabel 동일한 스타일 설정을 ProductPropertyValue 사용하도록 구성되었습니다.

.ProductPropertyLabel, .SupplierPropertyLabel
{
    font-weight: bold;
    text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
    padding-right: 35px;
}

변경한 후 브라우저를 통해 이 페이지를 방문합니다. 그림 5와 같이 각 DataList 항목은 공급자 이름을 텍스트로 표시하고 TextBoxes를 사용하여 주소, 도시 및 국가/지역을 표시합니다.

DataList의 각 공급업체는 편집 가능

그림 5: DataList의 각 공급업체가 편집 가능(전체 크기 이미지를 보려면 클릭)

2단계: 모두 업데이트 단추 추가

그림 5의 각 공급업체에는 TextBox에 주소, 도시 및 국가/지역 필드가 표시되지만 현재는 업데이트 단추를 사용할 수 없습니다. 항목당 업데이트 단추를 사용하는 대신, 완전히 편집 가능한 DataList를 사용하는 경우 일반적으로 페이지에는 DataList의 모든 레코드를 업데이트하는 단일 업데이트 모두 단추가 있습니다. 이 자습서에서는 페이지 맨 위에 하나씩, 아래쪽에 하나씩 두 개의 [모두 업데이트] 단추를 추가해 보겠습니다(두 단추를 클릭하면 동일한 효과가 있음).

먼저 DataList 위에 단추 웹 컨트롤을 추가하고 해당 ID 속성을 .로 UpdateAll1설정합니다. 다음으로 DataList 아래에 두 번째 단추 웹 컨트롤을 추가하고 해당 ID 컨트롤을 UpdateAll2.로 설정합니다. 두 단추의 Text 속성을 모두 업데이트하도록 설정합니다. 마지막으로 두 단추 이벤트에 대한 이벤트 처리기를 만듭니다 Click . 각 이벤트 처리기에서 업데이트 논리를 복제하는 대신 이벤트 처리기가 이 세 번째 메서드를 호출하도록 하여 해당 논리를 세 번째 메서드 UpdateAllSupplierAddresses로 리팩터링해 보겠습니다.

protected void UpdateAll1_Click(object sender, EventArgs e)
{
    UpdateAllSupplierAddresses();
}
protected void UpdateAll2_Click(object sender, EventArgs e)
{
    UpdateAllSupplierAddresses();
}
private void UpdateAllSupplierAddresses()
{
    // TODO: Write code to update _all_ of the supplier addresses in the DataList
}

그림 6은 모두 업데이트 단추가 추가된 후의 페이지를 보여 줍니다.

두 개의 업데이트 모든 단추가 페이지에 추가되었습니다.

그림 6: 페이지에 두 개의 업데이트 모든 단추가 추가되었습니다(전체 크기 이미지를 보려면 클릭).

3단계: 모든 공급업체 주소 정보 업데이트

모든 DataList 항목이 편집 인터페이스를 표시하고 모두 업데이트 단추가 추가되면 나머지 모든 항목은 일괄 업데이트를 수행하기 위해 코드를 작성하는 것입니다. 특히 DataList의 항목을 반복하고 각 항목에 대한 클래스 메서드 SuppliersBLLUpdateSupplierAddress 호출해야 합니다.

DataList를 구성하는 인스턴스의 DataListItem 컬렉션은 DataList의 Items 속성을 통해 액세스할 수 있습니다. 참조를 DataListItem사용하여 컬렉션에서 해당 SupplierID 컨트롤을 잡고 다음 코드와 DataKeys 같이 프로그래밍 방식으로 TextBox 웹 컨트롤을 ItemTemplate 참조할 수 있습니다.

private void UpdateAllSupplierAddresses()
{
    // Create an instance of the SuppliersBLL class
    SuppliersBLL suppliersAPI = new SuppliersBLL();
    // Iterate through the DataList's items
    foreach (DataListItem item in Suppliers.Items)
    {
        // Get the supplierID from the DataKeys collection
        int supplierID = Convert.ToInt32(Suppliers.DataKeys[item.ItemIndex]);
        // Read in the user-entered values
        TextBox address = (TextBox)item.FindControl("Address");
        TextBox city = (TextBox)item.FindControl("City");
        TextBox country = (TextBox)item.FindControl("Country");
        string addressValue = null, cityValue = null, countryValue = null;
        if (address.Text.Trim().Length > 0)
            addressValue = address.Text.Trim();
        if (city.Text.Trim().Length > 0)
              cityValue = city.Text.Trim();
        if (country.Text.Trim().Length > 0)
            countryValue = country.Text.Trim();
        // Call the SuppliersBLL class's UpdateSupplierAddress method
        suppliersAPI.UpdateSupplierAddress
            (supplierID, addressValue, cityValue, countryValue);
    }
}

사용자가 모두 업데이트 단추 중 하나를 클릭하면 메서드가 DataList의 각 UpdateAllSupplierAddressesDataListItem 단추를 Suppliers 반복하고 클래스의 SuppliersBLL 메서드를 UpdateSupplierAddress 호출하여 해당 값을 전달합니다. 주소, 도시 또는 국가/지역 패스에 대해 입력하지 않은 값은 빈 문자열이 아닌 값으로 NothingUpdateSupplierAddress , 기본 레코드 필드에 대한 데이터베이스 NULL 가 생성됩니다.

비고

향상된 기능으로 일괄 업데이트가 수행된 후 일부 확인 메시지를 제공하는 상태 레이블 웹 컨트롤을 페이지에 추가할 수 있습니다.

수정된 주소만 업데이트

이 자습서에 사용되는 일괄 업데이트 알고리즘은 주소 정보가 변경되었는지 여부에 관계없이 DataList의 모든UpdateSupplierAddress메서드를 호출 합니다. 이러한 블라인드 업데이트는 일반적으로 성능 문제가 아니지만 데이터베이스 테이블의 변경 내용을 감사하는 경우 불필요한 레코드로 이어질 수 있습니다. 예를 들어 트리거를 사용하여 테이블에 대한 모든 UPDATESuppliers 정보를 감사 테이블에 기록하는 경우 사용자가 [모두 업데이트] 단추를 클릭할 때마다 사용자가 변경했는지 여부에 관계없이 시스템의 각 공급업체에 대해 새 감사 레코드가 만들어집니다.

ADO.NET DataTable 및 DataAdapter 클래스는 수정, 삭제 및 새 레코드로 인해 데이터베이스 통신이 발생하는 일괄 업데이트를 지원하도록 설계되었습니다. DataTable의 각 행에는 RowState 행이 DataTable에 추가되었는지, 해당 행에서 삭제되었는지, 수정되었는지 또는 변경되지 않은 상태로 유지되는지를 나타내는 속성 이 있습니다. DataTable이 처음에 채워지면 모든 행이 변경되지 않은 것으로 표시됩니다. 행 열의 값을 변경하면 행이 수정된 것으로 표시됩니다.

SuppliersBLL 클래스에서 먼저 단일 공급자 레코드를 읽어 지정된 공급자의 주소 정보를 a SuppliersDataTable 로 업데이트한 다음, 다음 코드를 사용하여 , AddressCity 열 값을 설정합니다Country.

public bool UpdateSupplierAddress
    (int supplierID, string address, string city, string country)
{
    Northwind.SuppliersDataTable suppliers =
        Adapter.GetSupplierBySupplierID(supplierID);
    if (suppliers.Count == 0)
        // no matching record found, return false
        return false;
    else
    {
        Northwind.SuppliersRow supplier = suppliers[0];
        if (address == null)
            supplier.SetAddressNull();
        else
            supplier.Address = address;
        if (city == null)
            supplier.SetCityNull();
        else
            supplier.City = city;
        if (country == null)
            supplier.SetCountryNull();
        else
            supplier.Country = country;
        // Update the supplier Address-related information
        int rowsAffected = Adapter.Update(supplier);
        // Return true if precisely one row was updated,
        // otherwise false
        return rowsAffected == 1;
    }
}

이 코드는 값이 변경되었는지 여부에 관계없이 전달된 주소, 도시 및 국가/지역 값을 SuppliersRow in에 SuppliersDataTable 순진하게 할당합니다. 이러한 수정으로 인해 s SuppliersRow 속성이 RowState 수정된 것으로 표시됩니다. 데이터 액세스 계층 메서드 Update 가 호출되면 수정된 것으로 SupplierRow 확인되므로 데이터베이스에 UPDATE 명령을 보냅니다.

그러나 전달된 주소, 도시 및 국가/지역 값이 기존 값과 다른 SuppliersRow 경우에만 할당하도록 이 메서드에 코드를 추가했다고 가정해 보겠습니다. 주소, 도시 및 국가/지역이 기존 데이터와 동일한 경우 변경되지 SupplierRowRowState 않으며 s는 변경되지 않은 것으로 표시됩니다. 결과적으로 DAL 메서드 Update 가 호출되면 수정되지 않았기 때문에 데이터베이스 호출이 SuppliersRow 이루어지지 않습니다.

이 변경을 적용하려면 전달된 주소, 도시 및 국가/지역 값을 다음 코드로 맹목적으로 할당하는 문을 바꿉니다.

// Only assign the values to the SupplierRow's column values if they differ
if (address == null && !supplier.IsAddressNull())
    supplier.SetAddressNull();
else if ((address != null && supplier.IsAddressNull()) ||
         (!supplier.IsAddressNull() &&
         string.Compare(supplier.Address, address) != 0))
    supplier.Address = address;
if (city == null && !supplier.IsCityNull())
    supplier.SetCityNull();
else if ((city != null && supplier.IsCityNull()) ||
         (!supplier.IsCityNull() && string.Compare(supplier.City, city) != 0))
    supplier.City = city;
if (country == null && !supplier.IsCountryNull())
    supplier.SetCountryNull();
else if ((country != null && supplier.IsCountryNull()) ||
         (!supplier.IsCountryNull() &&
         string.Compare(supplier.Country, country) != 0))
    supplier.Country = country;

이 추가된 코드를 사용하여 DAL 메서드 Update 는 주소 관련 값이 변경된 레코드에 대해서만 문을 데이터베이스에 보냅니 UPDATE 다.

또는 전달된 주소 필드와 데이터베이스 데이터 간에 차이가 있는지 여부를 추적할 수 있으며, 없는 경우 DAL Update 메서드에 대한 호출을 무시하기만 하면 됩니다. 이 방법은 DB 직접 메서드를 사용하는 경우 DB 직접 메서드가 데이터베이스 호출이 실제로 필요한지 여부를 확인하기 위해 확인할 수 있는 SuppliersRow 인스턴스를 전달 RowState 하지 않으므로 잘 작동합니다.

비고

메서드가 UpdateSupplierAddress 호출될 때마다 데이터베이스를 호출하여 업데이트된 레코드에 대한 정보를 검색합니다. 그런 다음 데이터가 변경되면 테이블 행을 업데이트하기 위해 데이터베이스에 대한 또 다른 호출이 이루어집니다. 이 워크플로는 페이지의 모든UpdateSupplierAddressEmployeesDataTable 허용하는 메서드 오버로드를 만들어 최적화할 수 있습니다. 그런 다음 데이터베이스를 한 번 호출하여 테이블에서 모든 레코드 Suppliers 를 가져올 수 있습니다. 그런 다음 두 결과 집합을 열거할 수 있으며 변경이 발생한 레코드만 업데이트할 수 있습니다.

요약

이 자습서에서는 사용자가 여러 공급업체의 주소 정보를 신속하게 수정할 수 있도록 완전히 편집 가능한 DataList를 만드는 방법을 알아보았습니다. 먼저 DataList ItemTemplate의 공급자 주소, 도시 및 국가/지역 값에 대한 TextBox 웹 컨트롤 편집 인터페이스를 정의했습니다. 다음으로 DataList 위와 아래에 모든 업데이트 단추를 추가했습니다. 사용자가 변경한 후 모두 업데이트 단추 DataListItem 중 하나를 클릭하면 s가 열거되고 클래스 메서드 SuppliersBLL 를 호출합니다UpdateSupplierAddress.

행복한 프로그래밍!

작성자 정보

7개의 ASP/ASP.NET 책의 저자이자 4GuysFromRolla.com 창립자인 Scott Mitchell은 1998년부터 Microsoft 웹 기술을 연구해 왔습니다. Scott은 독립 컨설턴트, 트레이너 및 작가로 일합니다. 그의 최신 책은 Sams Teach Yourself ASP.NET 2.0 in 24 Hours입니다. 그에게 mitchell@4GuysFromRolla.com으로 연락할 수 있습니다.

특별히 감사드립니다.

이 자습서 시리즈는 많은 유용한 검토자가 검토했습니다. 이 자습서의 수석 검토자는 잭 존스와 켄 페스피사였습니다. 예정된 MSDN 문서를 검토하는 데 관심이 있으신가요? 그렇다면 mitchell@4GuysFromRolla.com으로 메시지를 보내 주세요.