SqlDataSource를 사용하여 낙관적 동시성 구현(VB)
작성자 : Scott Mitchell
이 자습서에서는 낙관적 동시성 제어의 필수 사항을 검토한 다음 SqlDataSource 컨트롤을 사용하여 구현하는 방법을 살펴봅니다.
소개
앞의 자습서에서는 SqlDataSource 컨트롤에 삽입, 업데이트 및 삭제 기능을 추가하는 방법을 검토했습니다. 요컨대, 이러한 기능을 제공하려면 컨트롤의 , 또는 속성에 해당 INSERT
, DeleteCommand
UpdateCommand
UPDATE
또는 DELETE
SQL 문을 , UpdateParameters
및 컬렉션의 InsertCommand
적절한 매개 변수InsertParameters
와 DeleteParameters
함께 지정해야 했습니다. 이러한 속성 및 컬렉션을 수동으로 지정할 수 있지만 데이터 원본 구성 마법사의 고급 단추는 문에 따라 이러한 문을 자동으로 만드는 , UPDATE
및 DELETE
문 생성 INSERT
확인란을 SELECT
제공합니다.
고급 SQL 생성 옵션 대화 상자에는 생성 INSERT
, UPDATE
및 문 확인란과 DELETE
함께 낙관적 동시성 사용 옵션이 포함되어 있습니다(그림 1 참조). 선택하면 WHERE
자동 생성된 및 DELETE
문의 절은 사용자가 마지막으로 데이터를 그리드에 로드한 UPDATE
이후 기본 데이터베이스 데이터가 수정되지 않은 경우에만 업데이트를 수행하거나 삭제하도록 수정됩니다.
그림 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.aspx
SqlDataSource
페이지를 엽니다. SqlDataSource 컨트롤을 도구 상자에서 Designer 끌어 속성을 ID
로 ProductsDataSourceWithOptimisticConcurrency
설정합니다. 그런 다음 컨트롤의 스마트 태그에서 데이터 원본 구성 링크를 클릭합니다. 마법사의 첫 번째 화면에서 작업 NORTHWINDConnectionString
하도록 선택하고 다음을 클릭합니다.
그림 4: 작업 NORTHWINDConnectionString
하도록 선택(전체 크기 이미지를 보려면 클릭)
이 예제에서는 사용자가 테이블을 편집할 수 있도록 하는 GridView를 Products
추가합니다. 따라서 문 선택 구성 화면에서 드롭다운 목록에서 테이블을 선택하고 Products
그림 5와 같이 , ProductName
, UnitPrice
및 Discontinued
열을 선택합니다ProductID
.
그림 5: 표에서 Products
, , ProductName
UnitPrice
및 Discontinued
열을 반환ProductID
합니다(전체 크기 이미지를 보려면 클릭).
열을 선택한 후 고급 단추를 클릭하여 고급 SQL 생성 옵션 대화 상자를 표시합니다. , UPDATE
및 문 생성 INSERT
및 DELETE
낙관적 동시성 사용 확인란을 선택하고 확인을 클릭합니다(스크린샷은 그림 1 참조). 다음, 마침을 차례로 클릭하여 마법사를 완료합니다.
데이터 원본 구성 마법사를 완료한 후 잠시 시간을 내어 결과 DeleteCommand
및 속성과 UpdateCommand
DeleteParameters
및 UpdateParameters
컬렉션을 살펴봅니다. 이 작업을 수행하는 가장 쉬운 방법은 왼쪽 아래 모서리에 있는 원본 탭을 클릭하여 페이지의 선언적 구문을 확인하는 것입니다. 다음 값을 찾을 수 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
각 매개 변수 컬렉션에 매개 변수를 추가하는 것 외에도 낙관적 동시성 사용 옵션을 선택하면 다음과 같은 두 가지 다른 속성이 조정됩니다.
ConflictDetection
속성을 (기본값)에서OverwriteChanges
로 변경합니다.CompareAllValues
OldValuesParameterFormatString
속성을 (기본값)에서 {0} original_{0} 로 변경합니다.
데이터 웹 컨트롤이 SqlDataSource 또는 Update()
Delete()
메서드를 호출하면 원래 값을 전달합니다. SqlDataSource의 ConflictDetection
속성이 로 CompareAllValues
설정된 경우 이러한 원래 값이 명령에 추가됩니다. 속성은 OldValuesParameterFormatString
이러한 원래 값 매개 변수에 사용되는 명명 패턴을 제공합니다. 데이터 원본 구성 마법사는 original_{0} 사용하여 및 DeleteCommand
속성 및 DeleteParameters
UpdateParameters
컬렉션의 UpdateCommand
각 원래 매개 변수 이름을 적절하게 지정합니다.
참고
SqlDataSource 컨트롤의 삽입 기능을 사용하지 않으므로 속성 및 해당 InsertParameters
컬렉션을 자유롭게 제거할 InsertCommand
수 있습니다.
값 올바르게 처리NULL
아쉽게도 낙관적 동시성을 사용할 때 데이터 원본 구성 마법사에서 자동으로 생성된 보강 UPDATE
및 DELETE
문은 값이 포함된 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
수 있습니다. 특정 레코드에 에 대한 UnitPrice
WHERE
값이 있는 NULL
경우 절 부분은 [UnitPrice] = @original_UnitPrice
항상 False를 반환하므로 항상 False NULL = NULL
로 평가됩니다. 따라서 및 DELETE
문 절은 업데이트 또는 삭제할 행을 반환하지 않으므로 값을 포함하는 NULL
레코드를 WHERE
편집하거나 삭제 UPDATE
할 수 없습니다.
참고
이 버그는 2004년 6월 SqlDataSource에서 잘못된 SQL 문을 생성 하여 Microsoft에 처음 보고되었으며 다음 버전의 ASP.NET 수정될 예정인 것으로 알려졌습니다.
이 문제를 해결하려면 값을 가질 수 있는 모든 열의 WHERE
및 DeleteCommand
속성 모두에서 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를 끌어서 로 ID
Products
설정합니다. GridView의 스마트 태그에서 1단계에 추가된 ProductsDataSourceWithOptimisticConcurrency
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단계: 동시성 위반이 발생한 시기 확인
동시성 위반은 변경 내용을 거부하므로 동시성 위반이 발생했을 때 사용자에게 경고하는 것이 좋습니다. 사용자에게 경고하려면 레이블 웹 컨트롤을 속성에 표시되는 페이지 ConcurrencyViolationMessage
Text
맨 위에 추가해 보겠습니다. 다른 사용자가 동시에 업데이트한 레코드를 업데이트하거나 삭제하려고 했습니다. 다른 사용자의 변경 내용을 검토한 다음 업데이트를 다시 실행하거나 삭제하세요. Label 컨트롤의 CssClass
속성을 경고로 설정합니다. 이 클래스는 텍스트를 빨간색, 기울임꼴, 굵게 및 큰 글꼴로 표시하는 에 정의된 Styles.css
CSS 클래스입니다. 마지막으로 레이블 Visible
및 EnableViewState
속성을 False
로 설정합니다. 이렇게 하면 명시적으로 속성을 True
로 설정한 포스트백만 제외하고 Label이 Visible
숨겨지게 됩니다.
그림 8: 경고 표시를 위해 페이지에 레이블 컨트롤 추가(전체 크기 이미지를 보려면 클릭)
업데이트 또는 삭제를 수행할 때 GridView RowUpdated
및 RowDeleted
이벤트 처리기는 데이터 원본 제어가 요청된 업데이트 또는 삭제를 수행한 후에 발생합니다. 이러한 이벤트 처리기의 작업에 의해 영향을 받은 행 수를 확인할 수 있습니다. 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 속성을 Visible
True
로 설정합니다ConcurrencyViolationMessage
. RowUpdated
또한 이벤트 처리기에서 속성을 true로 설정하여 GridView가 편집 모드로 KeepInEditMode
유지되도록 지시합니다. 이렇게 하려면 다른 사용자의 데이터가 편집 인터페이스에 로드되도록 데이터를 그리드에 다시 바인딩해야 합니다. 이 작업은 GridView의 DataBind()
메서드를 호출하여 수행됩니다.
그림 9에서 알 수 있듯이 이러한 두 이벤트 처리기를 사용하면 동시성 위반이 발생할 때마다 매우 눈에 띄는 메시지가 표시됩니다.
그림 9: 동시성 위반의 얼굴에 메시지가 표시됩니다(전체 크기 이미지를 보려면 클릭).
요약
여러 동시 사용자가 동일한 데이터를 편집할 수 있는 웹 애플리케이션을 만들 때 동시성 제어 옵션을 고려하는 것이 중요합니다. 기본적으로 ASP.NET 데이터 웹 컨트롤 및 데이터 원본 컨트롤은 동시성 제어를 사용하지 않습니다. 이 자습서에서 볼 수 있듯이 SqlDataSource를 사용하여 낙관적 동시성 제어를 구현하는 것은 비교적 빠르고 쉽습니다. SqlDataSource는 자동 생성된 UPDATE
및 문에 보강된 WHERE
절을 추가하는 데 필요한 대부분의 레그워크를 처리하지만 값 올바르게 처리 섹션에서 설명한 대로 값 열을 처리하는 NULL
데 NULL
는 몇 가지 미묘한 차이가 DELETE
있습니다.
이 자습서에서는 SqlDataSource에 대한 검사를 완료합니다. 나머지 자습서는 ObjectDataSource 및 계층화된 아키텍처를 사용하여 데이터 작업으로 돌아갑니다.
행복한 프로그래밍!
저자 정보
7개의 ASP/ASP.NET 책의 저자이자 4GuysFromRolla.com 창립자인 Scott Mitchell은 1998년부터 Microsoft 웹 기술을 연구해 왔습니다. Scott은 독립 컨설턴트, 트레이너 및 작가로 일합니다. 그의 최신 책은 샘스 자신을 가르친다 ASP.NET 2.0 24 시간. 그는 에서 찾을 수있는 그의 블로그를 통해 또는 에 mitchell@4GuysFromRolla.comhttp://ScottOnWriting.NET도달 할 수 있습니다.