SqlDataSource를 사용하여 낙관적 동시성 구현(VB)

작성자 : Scott Mitchell

PDF 다운로드

이 자습서에서는 낙관적 동시성 제어의 필수 사항을 검토한 다음 SqlDataSource 컨트롤을 사용하여 구현하는 방법을 살펴봅니다.

소개

앞의 자습서에서는 SqlDataSource 컨트롤에 삽입, 업데이트 및 삭제 기능을 추가하는 방법을 검토했습니다. 요컨대, 이러한 기능을 제공하려면 컨트롤의 , 또는 속성에 해당 INSERT, DeleteCommandUpdateCommandUPDATE또는 DELETE SQL 문을 , UpdateParameters및 컬렉션의 InsertCommand적절한 매개 변수InsertParametersDeleteParameters 함께 지정해야 했습니다. 이러한 속성 및 컬렉션을 수동으로 지정할 수 있지만 데이터 원본 구성 마법사의 고급 단추는 문에 따라 이러한 문을 자동으로 만드는 , UPDATEDELETE 문 생성 INSERT확인란을 SELECT 제공합니다.

고급 SQL 생성 옵션 대화 상자에는 생성 INSERT, UPDATE및 문 확인란과 DELETE 함께 낙관적 동시성 사용 옵션이 포함되어 있습니다(그림 1 참조). 선택하면 WHERE 자동 생성된 및 DELETE 문의 절은 사용자가 마지막으로 데이터를 그리드에 로드한 UPDATE 이후 기본 데이터베이스 데이터가 수정되지 않은 경우에만 업데이트를 수행하거나 삭제하도록 수정됩니다.

고급 SQL 생성 옵션 대화 상자에서 낙관적 동시성 지원을 추가할 수 있습니다.

그림 1: 고급 SQL 생성 옵션 대화 상자에서 낙관적 동시성 지원을 추가할 수 있습니다.

낙관적 동시성 구현 자습서에서 낙관적 동시성 제어의 기본 사항과 ObjectDataSource에 추가하는 방법을 살펴보했습니다. 이 자습서에서는 낙관적 동시성 제어의 필수 사항을 수정한 다음 SqlDataSource를 사용하여 구현하는 방법을 살펴봅니다.

낙관적 동시성 요약

여러 동시 사용자가 동일한 데이터를 편집하거나 삭제할 수 있는 웹 애플리케이션의 경우 한 사용자가 실수로 다른 변경 내용을 덮어쓸 수 있습니다. 낙관적 동시성 구현 자습서에서 다음 예제를 제공했습니다.

Jisun과 Sam이라는 두 사용자가 모두 방문자가 GridView 컨트롤을 통해 제품을 업데이트하고 삭제할 수 있는 애플리케이션의 페이지를 방문했다고 상상해 보세요. 둘 다 동시에 Chai에 대한 편집 단추를 클릭합니다. Jisun은 제품 이름을 Chai Tea로 변경하고 업데이트 단추를 클릭합니다. 순 결과는 데이터베이스로 전송되는 문입니다. 이 문은 UPDATE 제품의 모든 업데이트 가능한 필드를 설정합니다( Jisun은 하나의 필드 ProductName만 업데이트했음에도 불구하고 ). 이 시점에서 데이터베이스에는 이 특정 제품에 대한 Chai Tea, 카테고리 음료, 공급 업체 이국적인 액체 등이 있습니다. 그러나 Sam의 GridView 화면에는 편집 가능한 GridView 행의 제품 이름이 Chai로 표시됩니다. Jisun의 변경 내용이 커밋된 후 몇 초 후에 Sam은 범주를 Condiments로 업데이트하고 업데이트를 클릭합니다. 이렇게 하면 UPDATE 제품 이름을 Chai CategoryID , 해당 Condiments 범주 ID 등으로 설정하는 문이 데이터베이스로 전송됩니다. 제품 이름에 대한 Jisun의 변경 내용을 덮어씁니다.

그림 2에서는 이러한 상호 작용을 보여 줍니다.

두 사용자가 동시에 레코드를 업데이트하는 경우 한 사용자가 다른 사용자를 덮어쓸 가능성이 있습니다.

그림 2: 두 사용자가 동시에 레코드를 업데이트할 때 한 사용자가 다른 사용자를 덮어쓰도록 변경될 가능성이 있습니다(전체 크기 이미지를 보려면 클릭).

이 시나리오가 전개되지 않도록 하려면 동시성 제어 형식을 구현해야 합니다. 낙관적 동시성 이 자습서의 초점은 때때로 동시성 충돌이 있을 수 있지만 대부분의 경우 이러한 충돌이 발생하지 않는다는 가정하에 작동합니다. 따라서 충돌이 발생하는 경우 낙관적 동시성 제어는 다른 사용자가 동일한 데이터를 수정했기 때문에 변경 내용을 저장할 수 없음을 사용자에게 알릴 뿐입니다.

참고

동시성 충돌이 많거나 이러한 충돌을 견딜 수 없다고 가정하는 애플리케이션의 경우 비관적 동시성 제어를 대신 사용할 수 있습니다. 비관적 동시성 제어에 대한 보다 철저한 논의는 낙관적 동시성 구현 자습서를 참조하세요.

낙관적 동시성 제어는 업데이트 또는 삭제되는 레코드가 업데이트 또는 삭제 프로세스가 시작될 때와 동일한 값을 갖도록 하여 작동합니다. 예를 들어 편집 가능한 GridView에서 편집 단추를 클릭하면 레코드 값이 데이터베이스에서 읽혀지고 TextBoxes 및 기타 웹 컨트롤에 표시됩니다. 이러한 원래 값은 GridView에 의해 저장됩니다. 나중에 사용자가 변경하고 업데이트 단추를 UPDATE 클릭한 후 사용된 문은 원래 값과 새 값을 고려하고 사용자가 편집하기 시작한 원래 값이 데이터베이스에 있는 값과 동일한 경우에만 기본 데이터베이스 레코드를 업데이트해야 합니다. 그림 3에서는 이 이벤트 시퀀스를 보여 줍니다.

업데이트 또는 삭제가 성공하려면 원래 값이 현재 데이터베이스 값과 같아야 합니다.

그림 3: 업데이트 또는 삭제가 성공하려면 원래 값이 현재 데이터베이스 값과 같아야 합니다(전체 크기 이미지를 보려면 클릭).

낙관적 동시성을 구현하는 방법에는 다양한 방법이 있습니다(다양한 옵션을 간략하게 살펴보려면 Peter A. Bromberg낙관적 동시성 업데이트 논리 참조). SqlDataSource에서 사용하는 기술(및 데이터 액세스 계층에 사용되는 ADO.NET 형식화된 데이터 세트)은 절을 보강 WHERE 하여 모든 원래 값의 비교를 포함합니다. 예를 들어 다음 UPDATE 문은 현재 데이터베이스 값이 GridView에서 레코드를 업데이트할 때 원래 검색된 값과 동일한 경우에만 제품의 이름과 가격을 업데이트합니다. 및 @UnitPrice 매개 변수에는 @ProductName 사용자가 입력한 새 값이 포함되는 반면 @original_ProductName 편집 @original_UnitPrice 단추를 클릭할 때 원래 GridView에 로드된 값이 포함됩니다.

UPDATE Products SET
    ProductName = @ProductName,
    UnitPrice = @UnitPrice
WHERE
    ProductID = @original_ProductID AND
    ProductName = @original_ProductName AND
    UnitPrice = @original_UnitPrice

이 자습서에서 볼 수 있듯이 SqlDataSource를 사용하여 낙관적 동시성 제어를 사용하도록 설정하는 것은 확인란을 확인하는 것만큼 간단합니다.

1단계: 낙관적 동시성을 지원하는 SqlDataSource 만들기

먼저 폴더에서 OptimisticConcurrency.aspxSqlDataSource 페이지를 엽니다. SqlDataSource 컨트롤을 도구 상자에서 Designer 끌어 속성을 IDProductsDataSourceWithOptimisticConcurrency설정합니다. 그런 다음 컨트롤의 스마트 태그에서 데이터 원본 구성 링크를 클릭합니다. 마법사의 첫 번째 화면에서 작업 NORTHWINDConnectionString 하도록 선택하고 다음을 클릭합니다.

NORTHWINDConnectionString 작업 선택

그림 4: 작업 NORTHWINDConnectionString 하도록 선택(전체 크기 이미지를 보려면 클릭)

이 예제에서는 사용자가 테이블을 편집할 수 있도록 하는 GridView를 Products 추가합니다. 따라서 문 선택 구성 화면에서 드롭다운 목록에서 테이블을 선택하고 Products 그림 5와 같이 , ProductName, UnitPriceDiscontinued 열을 선택합니다ProductID.

Products 테이블에서 ProductID, ProductName, UnitPrice 및 불연속 열을 반환합니다.

그림 5: 표에서 Products , , ProductNameUnitPriceDiscontinued 열을 반환ProductID합니다(전체 크기 이미지를 보려면 클릭).

열을 선택한 후 고급 단추를 클릭하여 고급 SQL 생성 옵션 대화 상자를 표시합니다. , UPDATE및 문 생성 INSERTDELETE 낙관적 동시성 사용 확인란을 선택하고 확인을 클릭합니다(스크린샷은 그림 1 참조). 다음, 마침을 차례로 클릭하여 마법사를 완료합니다.

데이터 원본 구성 마법사를 완료한 후 잠시 시간을 내어 결과 DeleteCommand 및 속성과 UpdateCommandDeleteParametersUpdateParameters 컬렉션을 살펴봅니다. 이 작업을 수행하는 가장 쉬운 방법은 왼쪽 아래 모서리에 있는 원본 탭을 클릭하여 페이지의 선언적 구문을 확인하는 것입니다. 다음 값을 찾을 수 UpdateCommand 있습니다.

UPDATE [Products] SET
     [ProductName] = @ProductName,
     [UnitPrice] = @UnitPrice,
     [Discontinued] = @Discontinued
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     [UnitPrice] = @original_UnitPrice AND
     [Discontinued] = @original_Discontinued

컬렉션에 7개의 매개 변수가 있습니다 UpdateParameters .

<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
    runat="server" ...>
    <DeleteParameters>
      ...
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="UnitPrice" Type="Decimal" />
        <asp:Parameter Name="Discontinued" Type="Boolean" />
        <asp:Parameter Name="original_ProductID" Type="Int32" />
        <asp:Parameter Name="original_ProductName" Type="String" />
        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
        <asp:Parameter Name="original_Discontinued" Type="Boolean" />
    </UpdateParameters>
    ...
</asp:SqlDataSource>

마찬가지로 속성 및 DeleteParameters 컬렉션은 DeleteCommand 다음과 같아야 합니다.

DELETE FROM [Products]
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     [UnitPrice] = @original_UnitPrice AND
     [Discontinued] = @original_Discontinued
<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
    runat="server" ...>
    <DeleteParameters>
        <asp:Parameter Name="original_ProductID" Type="Int32" />
        <asp:Parameter Name="original_ProductName" Type="String" />
        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
        <asp:Parameter Name="original_Discontinued" Type="Boolean" />
    </DeleteParameters>
    <UpdateParameters>
        ...
    </UpdateParameters>
    ...
</asp:SqlDataSource>

DeleteCommand 속성의 UpdateCommand 절을 보강하고 WHERE 각 매개 변수 컬렉션에 매개 변수를 추가하는 것 외에도 낙관적 동시성 사용 옵션을 선택하면 다음과 같은 두 가지 다른 속성이 조정됩니다.

데이터 웹 컨트롤이 SqlDataSource 또는 Update()Delete() 메서드를 호출하면 원래 값을 전달합니다. SqlDataSource의 ConflictDetection 속성이 로 CompareAllValues설정된 경우 이러한 원래 값이 명령에 추가됩니다. 속성은 OldValuesParameterFormatString 이러한 원래 값 매개 변수에 사용되는 명명 패턴을 제공합니다. 데이터 원본 구성 마법사는 original_{0} 사용하여 및 DeleteCommand 속성 및 DeleteParametersUpdateParameters 컬렉션의 UpdateCommand 각 원래 매개 변수 이름을 적절하게 지정합니다.

참고

SqlDataSource 컨트롤의 삽입 기능을 사용하지 않으므로 속성 및 해당 InsertParameters 컬렉션을 자유롭게 제거할 InsertCommand 수 있습니다.

값 올바르게 처리NULL

아쉽게도 낙관적 동시성을 사용할 때 데이터 원본 구성 마법사에서 자동으로 생성된 보강 UPDATEDELETE 문은 값이 포함된 NULL 레코드에서 작동하지 않습니다. 이유를 확인하려면 SqlDataSource의 UpdateCommand를 고려하세요.

UPDATE [Products] SET
     [ProductName] = @ProductName,
     [UnitPrice] = @UnitPrice,
     [Discontinued] = @Discontinued
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     [UnitPrice] = @original_UnitPrice AND
     [Discontinued] = @original_Discontinued

UnitPrice 테이블의 열에는 값이 Products 있을 NULL 수 있습니다. 특정 레코드에 에 대한 UnitPriceWHERE 값이 있는 NULL 경우 절 부분은 [UnitPrice] = @original_UnitPrice 항상 False를 반환하므로 항상 False NULL = NULL 로 평가됩니다. 따라서 및 DELETE 문 절은 업데이트 또는 삭제할 행을 반환하지 않으므로 값을 포함하는 NULL 레코드를 WHERE 편집하거나 삭제 UPDATE 할 수 없습니다.

참고

이 버그는 2004년 6월 SqlDataSource에서 잘못된 SQL 문을 생성 하여 Microsoft에 처음 보고되었으며 다음 버전의 ASP.NET 수정될 예정인 것으로 알려졌습니다.

이 문제를 해결하려면 값을 가질 수 있는 모든 열의 WHEREDeleteCommand 속성 모두에서 UpdateCommand 절을 수동으로 업데이트해야 NULL 합니다. 일반적으로 다음으로 변경 [ColumnName] = @original_ColumnName 합니다.

(
   ([ColumnName] IS NULL AND @original_ColumnName IS NULL)
     OR
   ([ColumnName] = @original_ColumnName)
)

이 수정은 선언적 태그를 통해, 속성 창 UpdateQuery 또는 DeleteQuery 옵션을 통해 또는 데이터 원본 구성 마법사의 사용자 지정 SQL 문 또는 저장 프로시저 지정 옵션의 UPDATE 및 DELETE 탭을 통해 직접 수행할 수 있습니다. 다시 말하지만, 값을 포함 NULL 할 수 있는 및 DeleteCommand s 절의 WHERE모든 열에 UpdateCommand 대해 이 수정이 이루어져야 합니다.

이 값을 예제에 적용하면 다음과 같은 수정된 UpdateCommand 값과 DeleteCommand 값이 생성됩니다.

UPDATE [Products] SET
     [ProductName] = @ProductName,
     [UnitPrice] = @UnitPrice,
     [Discontinued] = @Discontinued
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
        OR ([UnitPrice] = @original_UnitPrice)) AND
     [Discontinued] = @original_Discontinued
DELETE FROM [Products]
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
        OR ([UnitPrice] = @original_UnitPrice)) AND
     [Discontinued] = @original_Discontinued

2단계: 편집 및 삭제 옵션을 사용하여 GridView 추가

낙관적 동시성을 지원하도록 구성된 SqlDataSource를 사용하면 이 동시성 컨트롤을 활용하는 페이지에 데이터 웹 컨트롤을 추가할 수 있습니다. 이 자습서에서는 편집 및 삭제 기능을 모두 제공하는 GridView를 추가해 보겠습니다. 이렇게 하려면 도구 상자에서 Designer GridView를 끌어서 로 IDProducts설정합니다. GridView의 스마트 태그에서 1단계에 추가된 ProductsDataSourceWithOptimisticConcurrency SqlDataSource 컨트롤에 바인딩합니다. 마지막으로 스마트 태그에서 편집 사용 및 삭제 사용 옵션을 검사.

GridView를 SqlDataSource에 바인딩하고 편집 및 삭제 사용

그림 6: GridView를 SqlDataSource에 바인딩하고 편집 및 삭제 사용(전체 크기 이미지를 보려면 클릭)

GridView를 추가한 후 BoundField를 ProductID 제거하고, BoundField의 HeaderText 속성을 Product로 변경 ProductName 하고, 해당 속성이 단순히 Price가 되도록 BoundField를 HeaderText 업데이트 UnitPrice 하여 모양을 구성합니다. 값에 RequiredFieldValidator를 포함하고 값에 ProductName CompareValidator UnitPrice 를 포함하도록 편집 인터페이스를 개선하는 것이 좋습니다(올바른 형식의 숫자 값인지 확인). GridView 의 편집 인터페이스 사용자 지정 에 대한 자세한 내용은 데이터 수정 인터페이스 사용자 지정 자습서를 참조하세요.

참고

GridView에서 SqlDataSource로 전달된 원래 값이 뷰 상태에 저장되므로 GridView의 뷰 상태를 사용하도록 설정해야 합니다.

GridView를 수정한 후 GridView 및 SqlDataSource 선언적 태그는 다음과 유사하게 표시됩니다.

<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
    runat="server" ConflictDetection="CompareAllValues"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    DeleteCommand=
        "DELETE FROM [Products]
         WHERE [ProductID] = @original_ProductID
         AND [ProductName] = @original_ProductName
         AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
              OR ([UnitPrice] = @original_UnitPrice))
         AND [Discontinued] = @original_Discontinued"
    OldValuesParameterFormatString=
        "original_{0}"
    SelectCommand=
        "SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued]
         FROM [Products]"
    UpdateCommand=
        "UPDATE [Products]
         SET [ProductName] = @ProductName, [UnitPrice] = @UnitPrice,
            [Discontinued] = @Discontinued
         WHERE [ProductID] = @original_ProductID
         AND [ProductName] = @original_ProductName
         AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
            OR ([UnitPrice] = @original_UnitPrice))
        AND [Discontinued] = @original_Discontinued">
    <DeleteParameters>
        <asp:Parameter Name="original_ProductID" Type="Int32" />
        <asp:Parameter Name="original_ProductName" Type="String" />
        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
        <asp:Parameter Name="original_Discontinued" Type="Boolean" />
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="UnitPrice" Type="Decimal" />
        <asp:Parameter Name="Discontinued" Type="Boolean" />
        <asp:Parameter Name="original_ProductID" Type="Int32" />
        <asp:Parameter Name="original_ProductName" Type="String" />
        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
        <asp:Parameter Name="original_Discontinued" Type="Boolean" />
    </UpdateParameters>
</asp:SqlDataSource>
<asp:GridView ID="Products" runat="server"
    AutoGenerateColumns="False" DataKeyNames="ProductID"
    DataSourceID="ProductsDataSourceWithOptimisticConcurrency">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="Price"
            SortExpression="UnitPrice" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
    </Columns>
</asp:GridView>

낙관적 동시성 컨트롤의 작동을 확인하려면 두 개의 브라우저 창을 열고 둘 다에서 페이지를 로드 OptimisticConcurrency.aspx 합니다. 두 브라우저에서 첫 번째 제품의 편집 단추를 클릭합니다. 한 브라우저에서 제품 이름을 변경하고 업데이트를 클릭합니다. 브라우저는 포스트백되고 GridView는 편집 전 모드로 돌아가 방금 편집한 레코드의 새 제품 이름을 표시합니다.

두 번째 브라우저 창에서 가격을 변경하고(제품 이름을 원래 값으로 유지) 업데이트를 클릭합니다. 포스트백 시 그리드는 편집 전 모드로 반환되지만 가격 변경 내용은 기록되지 않습니다. 두 번째 브라우저는 새 제품 이름과 동일한 값을 이전 가격으로 표시합니다. 두 번째 브라우저 창에서 변경된 내용이 손실되었습니다. 또한 동시성 위반이 방금 발생했음을 나타내는 예외나 메시지가 없으므로 변경 내용이 다소 조용히 손실되었습니다.

두 번째 브라우저 창의 변경 내용이 자동으로 손실되었습니다.

그림 7: 두 번째 브라우저 창의 변경 내용이 자동으로 손실됨(전체 크기 이미지를 보려면 클릭)

두 번째 브라우저의 변경 내용이 커밋되지 않은 이유는 문 WHERE 절이 모든 레코드를 UPDATE 필터링하여 행에 영향을 주지 않았기 때문입니다. 문을 다시 살펴보겠습니다 UPDATE .

UPDATE [Products] SET
     [ProductName] = @ProductName,
     [UnitPrice] = @UnitPrice,
     [Discontinued] = @Discontinued
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL) OR
        ([UnitPrice] = @original_UnitPrice)) AND
     [Discontinued] = @original_Discontinued

두 번째 브라우저 창에서 레코드를 업데이트하면 절에 WHERE 지정된 원래 제품 이름이 기존 제품 이름과 일치하지 않습니다(첫 번째 브라우저에서 변경되었기 때문에). 따라서 문 [ProductName] = @original_ProductName 은 False를 반환하고 는 레코드에 UPDATE 영향을 주지 않습니다.

참고

삭제는 동일한 방식으로 작동합니다. 두 개의 브라우저 창이 열려 있는 상태에서 먼저 지정된 제품을 편집한 다음 변경 내용을 저장합니다. 한 브라우저에서 변경 내용을 저장한 후 다른 브라우저에서 동일한 제품의 삭제 단추를 클릭합니다. 문 WHERE 절에서 원래 값이 DELETE 일치하지 않으므로 삭제가 자동으로 실패합니다.

두 번째 브라우저 창의 최종 사용자 관점에서 업데이트 단추를 클릭한 후 그리드가 편집 전 모드로 돌아옵니다. 그러나 변경 내용이 손실되었습니다. 그러나 변경 내용이 달라지지 않았다는 시각적 피드백은 없습니다. 사용자의 변경 내용이 동시성 위반으로 손실되는 경우 사용자에게 알리고 그리드를 편집 모드로 유지하는 것이 가장 좋습니다. 이 작업을 수행하는 방법을 살펴보겠습니다.

3단계: 동시성 위반이 발생한 시기 확인

동시성 위반은 변경 내용을 거부하므로 동시성 위반이 발생했을 때 사용자에게 경고하는 것이 좋습니다. 사용자에게 경고하려면 레이블 웹 컨트롤을 속성에 표시되는 페이지 ConcurrencyViolationMessageText 맨 위에 추가해 보겠습니다. 다른 사용자가 동시에 업데이트한 레코드를 업데이트하거나 삭제하려고 했습니다. 다른 사용자의 변경 내용을 검토한 다음 업데이트를 다시 실행하거나 삭제하세요. Label 컨트롤의 CssClass 속성을 경고로 설정합니다. 이 클래스는 텍스트를 빨간색, 기울임꼴, 굵게 및 큰 글꼴로 표시하는 에 정의된 Styles.css CSS 클래스입니다. 마지막으로 레이블 VisibleEnableViewState 속성을 False로 설정합니다. 이렇게 하면 명시적으로 속성을 True로 설정한 포스트백만 제외하고 Label이 Visible 숨겨지게 됩니다.

페이지에 레이블 컨트롤을 추가하여 경고 표시

그림 8: 경고 표시를 위해 페이지에 레이블 컨트롤 추가(전체 크기 이미지를 보려면 클릭)

업데이트 또는 삭제를 수행할 때 GridView RowUpdatedRowDeleted 이벤트 처리기는 데이터 원본 제어가 요청된 업데이트 또는 삭제를 수행한 후에 발생합니다. 이러한 이벤트 처리기의 작업에 의해 영향을 받은 행 수를 확인할 수 있습니다. 0개의 행이 영향을 받은 경우 레이블을 ConcurrencyViolationMessage 표시하려고 합니다.

RowDeleted 이벤트 모두 RowUpdated 에 대한 이벤트 처리기를 만들고 다음 코드를 추가합니다.

Protected Sub Products_RowUpdated(sender As Object, e As GridViewUpdatedEventArgs) _
    Handles Products.RowUpdated
    If e.AffectedRows = 0 Then
        ConcurrencyViolationMessage.Visible = True
        e.KeepInEditMode = True
        ' Rebind the data to the GridView to show the latest changes
        Products.DataBind()
    End If
End Sub
Protected Sub Products_RowDeleted(sender As Object, e As GridViewDeletedEventArgs) _
    Handles Products.RowDeleted
    If e.AffectedRows = 0 Then
        ConcurrencyViolationMessage.Visible = True
    End If
End Sub

두 이벤트 처리기에서 속성을 검사 e.AffectedRows 0이면 Label 속성을 VisibleTrue로 설정합니다ConcurrencyViolationMessage. RowUpdated 또한 이벤트 처리기에서 속성을 true로 설정하여 GridView가 편집 모드로 KeepInEditMode 유지되도록 지시합니다. 이렇게 하려면 다른 사용자의 데이터가 편집 인터페이스에 로드되도록 데이터를 그리드에 다시 바인딩해야 합니다. 이 작업은 GridView의 DataBind() 메서드를 호출하여 수행됩니다.

그림 9에서 알 수 있듯이 이러한 두 이벤트 처리기를 사용하면 동시성 위반이 발생할 때마다 매우 눈에 띄는 메시지가 표시됩니다.

동시성 위반의 얼굴에 메시지가 표시됩니다.

그림 9: 동시성 위반의 얼굴에 메시지가 표시됩니다(전체 크기 이미지를 보려면 클릭).

요약

여러 동시 사용자가 동일한 데이터를 편집할 수 있는 웹 애플리케이션을 만들 때 동시성 제어 옵션을 고려하는 것이 중요합니다. 기본적으로 ASP.NET 데이터 웹 컨트롤 및 데이터 원본 컨트롤은 동시성 제어를 사용하지 않습니다. 이 자습서에서 볼 수 있듯이 SqlDataSource를 사용하여 낙관적 동시성 제어를 구현하는 것은 비교적 빠르고 쉽습니다. SqlDataSource는 자동 생성된 UPDATE 및 문에 보강된 WHERE 절을 추가하는 데 필요한 대부분의 레그워크를 처리하지만 값 올바르게 처리 섹션에서 설명한 대로 값 열을 처리하는 NULLNULL 는 몇 가지 미묘한 차이가 DELETE 있습니다.

이 자습서에서는 SqlDataSource에 대한 검사를 완료합니다. 나머지 자습서는 ObjectDataSource 및 계층화된 아키텍처를 사용하여 데이터 작업으로 돌아갑니다.

행복한 프로그래밍!

저자 정보

7개의 ASP/ASP.NET 책의 저자이자 4GuysFromRolla.com 창립자인 Scott Mitchell은 1998년부터 Microsoft 웹 기술을 연구해 왔습니다. Scott은 독립 컨설턴트, 트레이너 및 작가로 일합니다. 그의 최신 책은 샘스 자신을 가르친다 ASP.NET 2.0 24 시간. 그는 에서 찾을 수있는 그의 블로그를 통해 또는 에 mitchell@4GuysFromRolla.comhttp://ScottOnWriting.NET도달 할 수 있습니다.