Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Autor : Scott Mitchell
W tym samouczku zapoznamy się z podstawowymi elementami optymistycznej kontroli współbieżności, a następnie dowiesz się, jak zaimplementować ją przy użyciu kontrolki SqlDataSource.
Wprowadzenie
W poprzednim samouczku sprawdziliśmy, jak dodać funkcje wstawiania, aktualizowania i usuwania do kontrolki SqlDataSource. Krótko mówiąc, aby udostępnić te funkcje, musieliśmy określić odpowiednią instrukcję SQL INSERT, UPDATE lub DELETE we właściwości kontrolki InsertCommand, UpdateCommand lub DeleteCommand, wraz z odpowiednimi parametrami w kolekcjach InsertParameters, UpdateParameters i DeleteParameters. Chociaż te właściwości i kolekcje można określić ręcznie, przycisk "Zaawansowane" w kreatorze konfigurowania źródła danych zawiera pole wyboru "Generuj instrukcje INSERT, UPDATE i DELETE", które automatycznie utworzy te instrukcje na podstawie instrukcji SELECT.
Wraz z polem wyboru dotyczącego instrukcji Generuj INSERT, UPDATE i DELETE okno dialogowe Zaawansowane opcje generowania SQL zawiera opcję Użyj optymistycznej współbieżności (zobacz Rysunek 1). Po sprawdzeniu klauzule WHERE w automatycznie generowanych instrukcjach UPDATE i DELETE są modyfikowane tak, aby wykonywać aktualizację lub usunięcie tylko wtedy, gdy bazowe dane bazy danych nie zostały zmodyfikowane od czasu, gdy użytkownik ostatnio załadował dane do siatki.
Rysunek 1. Możesz dodać obsługę optymistycznej współbieżności z okna dialogowego zaawansowanych opcji generowania SQL.
Po powrocie do samouczka Implementowanie optymistycznej współbieżności przeanalizowaliśmy podstawy optymistycznej kontroli współbieżności i sposób dodawania jej do obiektu ObjectDataSource. W tym przewodniku ponownie omówimy podstawowe aspekty kontroli optymistycznej współbieżności oraz omówimy, jak ją zaimplementować przy użyciu SqlDataSource.
Podsumowanie optymistycznej współbieżności
W przypadku aplikacji internetowych, które umożliwiają wielu, równoczesnym użytkownikom edytowanie lub usuwanie tych samych danych, istnieje możliwość, że jeden użytkownik może przypadkowo zastąpić inne zmiany. W tutorialu zatytułowanym Implementowanie optymistycznej współbieżności podałem następujący przykład:
Załóżmy, że dwóch użytkowników, Jisun i Sam, odwiedzało stronę w aplikacji, która zezwalała odwiedzającym na aktualizowanie i usuwanie produktów za pomocą kontrolki GridView. Obaj klikają przycisk Edytuj dla Chai jednocześnie. Jisun zmienia nazwę produktu na Chai Tea i klika przycisk Aktualizuj. Ostateczny wynik to zapytanie UPDATE wysyłane do bazy danych, które ustawia wszystkie pola z możliwością aktualizacji produktu (mimo że Jisun zaktualizowała tylko jedno pole, ProductName). W tym momencie baza danych ma wartości Chai Tea, kategorię Napoje, dostawca Egzotyczne płyny itd. dla tego konkretnego produktu. Jednak GridView na ekranie Sama nadal pokazuje w edytowalnym wierszu GridView nazwę produktu jako Chai. Kilka sekund po zatwierdzeniu zmian wprowadzonych przez Jisun, Sam aktualizuje kategorię na Przyprawy i klika Aktualizuj. Spowoduje to, że instrukcja UPDATE zostanie wysłana do bazy danych, która ustawia nazwę produktu na Chai, wartość CategoryID na odpowiadający identyfikator kategorii Condiments, i tak dalej. Zmiany w nazwie produktu Jisun zostały zastąpione.
Rysunek 2 ilustruje tę interakcję.
Rysunek 2: Gdy dwóch użytkowników jednocześnie zaktualizuje rekord, istnieje możliwość, że zmiany jednego użytkownika zastąpią zmiany drugiego. (kliknij, aby wyświetlić obraz w pełnym rozmiarze)
Aby zapobiec rozwinięciu tego scenariusza, należy zaimplementować formę kontroli współbieżności . Optymistyczna współbieżność koncentruje się na założeniu, że podczas gdy konflikty współbieżności mogą występować co jakiś czas, zdecydowana większość czasu takich konfliktów nie wystąpi. W związku z tym, jeśli wystąpi konflikt, optymistyczna kontrola współbieżności po prostu informuje użytkownika, że nie można zapisać ich zmian, ponieważ inny użytkownik zmodyfikował te same dane.
Uwaga / Notatka
W przypadku aplikacji, w których zakłada się, że wystąpi wiele konfliktów współbieżności lub jeśli takie konflikty nie są tolerowane, można zamiast tego użyć pesymistycznej kontroli współbieżności. Odwołaj się ponownie do samouczka Implementacja optymistycznej współbieżności, aby uzyskać bardziej szczegółową dyskusję na temat pesymistycznej kontroli współbieżności.
Optymistyczna kontrola współbieżności działa, upewniając się, że rekord aktualizowany lub usuwany ma te same wartości co podczas uruchamiania procesu aktualizowania lub usuwania. Na przykład po kliknięciu przycisku Edytuj w edytowalnej kontrolce GridView wartości rekordów są odczytywane z bazy danych i wyświetlane w polach tekstowych oraz innych kontrolkach sieci Web. Te oryginalne wartości są zapisywane przez kontrolkę GridView. Później, gdy użytkownik wprowadzi swoje zmiany i kliknie przycisk Aktualizuj, UPDATE użyta instrukcja musi uwzględniać oryginalne wartości oraz nowe wartości i aktualizować rekord w bazie danych tylko wtedy, gdy oryginalne wartości, które użytkownik zaczął edytować, są identyczne z wartościami nadal znajdującymi się w bazie danych. Rysunek 3 przedstawia tę sekwencję zdarzeń.
Rysunek 3. Aby aktualizacja lub usunięcie powiodło się, oryginalne wartości muszą być równe bieżącym wartościom bazy danych (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Istnieją różne podejścia do implementowania optymistycznej współbieżności (zobacz Optymistyczna logika aktualizacji współbieżnościPetera A. Bromberga, aby zapoznać się z kilkoma opcjami). Technika używana przez usługę SqlDataSource (a także zestawy danych typu ADO.NET używane w warstwie dostępu do danych) rozszerza WHERE klauzulę w celu uwzględnienia porównania wszystkich oryginalnych wartości. Poniższa UPDATE instrukcja, na przykład, aktualizuje nazwę i cenę produktu tylko wtedy, gdy bieżące wartości bazy danych są równe wartościom, które zostały pierwotnie pobrane podczas aktualizacji rekordu w widoku siatki. Parametry @ProductName i @UnitPrice zawierają nowe wartości wprowadzone przez użytkownika, natomiast @original_ProductName i @original_UnitPrice zawierają wartości, które zostały pierwotnie załadowane do kontrolki GridView po kliknięciu przycisku Edytuj:
UPDATE Products SET
ProductName = @ProductName,
UnitPrice = @UnitPrice
WHERE
ProductID = @original_ProductID AND
ProductName = @original_ProductName AND
UnitPrice = @original_UnitPrice
Jak zobaczymy w tym samouczku, włączenie optymistycznej kontroli współbieżności za pomocą obiektu SqlDataSource jest tak proste, jak zaznaczenie pola wyboru.
Krok 1. Tworzenie zasobu SqlDataSource obsługującego optymistyczną współbieżność
Rozpocznij od otwarcia OptimisticConcurrency.aspx strony z SqlDataSource folderu . Przeciągnij kontrolkę SqlDataSource z Przybornika do Projektanta, a następnie ustaw jej właściwość ID na ProductsDataSourceWithOptimisticConcurrency. Następnie kliknij link Konfiguruj źródło danych z tagu inteligentnego kontrolki. Na pierwszym ekranie kreatora wybierz pracę z elementem NORTHWINDConnectionString i kliknij przycisk Dalej.
Rysunek 4. Wybierz pracę z elementem NORTHWINDConnectionString (Kliknij, aby wyświetlić obraz o pełnym rozmiarze)
W tym przykładzie dodamy kontrolkę GridView, która umożliwia użytkownikom edytowanie Products tabeli. W związku z tym na ekranie Konfigurowanie instrukcji Select wybierz tabelę Products z listy rozwijanej i wybierz kolumny ProductID, ProductName, UnitPrice oraz Discontinued, jak pokazano na rysunku 5.
Rysunek 5. Z Products tabeli zwróć kolumny ProductID, ProductName, UnitPricei Discontinued (kliknij, aby wyświetlić obraz pełnowymiarowy)
Po wybraniu kolumn kliknij przycisk Zaawansowane, aby wyświetlić okno dialogowe Zaawansowane opcje generacji SQL. Zaznacz pola wyboru Generuj INSERT i UPDATE i DELETE oraz pola Użyj optymistycznej współbieżności, a następnie kliknij przycisk OK (podgląd w Rysunku 1 przedstawia zrzut ekranu). Zakończ pracę kreatora, klikając przycisk Dalej, a następnie zakończ.
Po ukończeniu pracy kreatora Konfigurowanie źródła danych, poświęć chwilę, aby zbadać wynikowe właściwości DeleteCommand i UpdateCommand oraz kolekcje DeleteParameters i UpdateParameters. Najprostszym sposobem wykonania tej czynności jest kliknięcie karty Źródło w lewym dolnym rogu w celu wyświetlenia składni deklaratywnej strony. W tym miejscu znajdziesz wartość 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
Z siedmioma parametrami w kolekcji 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>
Podobnie DeleteCommand właściwość i DeleteParameters kolekcja powinny wyglądać następująco:
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>
Oprócz rozszerzania klauzul WHERE właściwości UpdateCommand i DeleteCommand (oraz dodawania dodatkowych parametrów do odpowiednich kolekcji parametrów), wybranie opcji Użyj optymistycznej współbieżności dostosowuje jeszcze dwie inne właściwości:
-
ConflictDetectionZmienia właściwość zOverwriteChanges(wartość domyślna) naCompareAllValues -
OldValuesParameterFormatStringZmienia właściwość z {0} (wartość domyślna) na original_{0} .
Kiedy kontrolka danych sieci Web wywoła metodę Update() lub Delete() z SqlDataSource, przekazuje oryginalne wartości. Jeśli właściwość sqlDataSource jest ustawiona ConflictDetection na CompareAllValues, do polecenia zostaną dodane te oryginalne wartości. Właściwość OldValuesParameterFormatString udostępnia wzorzec nazewnictwa używany dla tych oryginalnych parametrów wartości. Kreator konfigurowania źródła danych używa original_{0} i nazwy każdego oryginalnego parametru UpdateCommand we właściwościach i DeleteCommand i UpdateParametersDeleteParameters kolekcjach odpowiednio.
Uwaga / Notatka
Ponieważ nie używamy możliwości wstawiania kontrolki SqlDataSource, możesz usunąć InsertCommand właściwość i jej InsertParameters kolekcję.
Prawidłowe zarządzanieNULLwartościami
Niestety, rozszerzone instrukcje UPDATE i DELETE, które są automatycznie generowane przez kreatora konfigurowania źródła danych przy użyciu optymistycznej współbieżności, nie działają z rekordami zawierającymi wartości NULL. Aby dowiedzieć się, dlaczego warto rozważyć usługę SqlDataSource s 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
Kolumna UnitPrice w Products tabeli może zawierać NULL wartości. Jeśli określony rekord ma wartość NULL dla UnitPrice, część klauzuli WHERE[UnitPrice] = @original_UnitPrice będzie zawsze oceniać się na False, ponieważ NULL = NULL zawsze zwraca False. W związku z tym rekordy zawierające NULL wartości nie mogą być edytowane ani usuwane, ponieważ instrukcje UPDATE oraz klauzule DELETEWHERE nie będą zwracać żadnych wierszy do aktualizacji ani usunięcia.
Uwaga / Notatka
Ta usterka została po raz pierwszy zgłoszona firmie Microsoft w czerwcu 2004 r. w usłudze SqlDataSource generuje nieprawidłowe instrukcje SQL i podobno ma zostać naprawiona w następnej wersji ASP.NET.
Aby rozwiązać ten problem, musimy ręcznie zaktualizować klauzule WHERE zarówno we właściwościach UpdateCommand, jak i DeleteCommand dla wszystkich kolumn, które mogą mieć wartości NULL. Ogólnie rzecz biorąc, zmień na [ColumnName] = @original_ColumnName :
(
([ColumnName] IS NULL AND @original_ColumnName IS NULL)
OR
([ColumnName] = @original_ColumnName)
)
Tę modyfikację można wprowadzić bezpośrednio za pomocą znaczników deklaratywnych, za pośrednictwem opcji UpdateQuery lub DeleteQuery w oknie Właściwości lub za pomocą kart UPDATE i DELETE w opcji Określenie niestandardowej instrukcji SQL lub procedury składowanej w kreatorze Konfigurowania źródła danych. Ponownie należy wprowadzić tę modyfikację dla każdej kolumny w klauzuli UpdateCommand i DeleteCommand s WHERE, która może zawierać NULL wartości.
Zastosowanie tego do naszego przykładu powoduje następujące modyfikacje UpdateCommand i DeleteCommand wartości:
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
Krok 2. Dodawanie kontrolki GridView z opcjami edycji i usuwania
Po skonfigurowaniu usługi SqlDataSource do obsługi optymistycznej współbieżności pozostaje dodanie kontrolki sieci Web danych do strony korzystającej z tej kontrolki współbieżności. Na potrzeby tego samouczka dodajmy element GridView, który zapewnia zarówno funkcję edytowania, jak i usuwania. Aby to zrobić, przeciągnij kontrolkę GridView z przybornika na projektanta i ustaw dla niej ID na Products. Używając inteligentnej etykiety GridView, powiąż ją z kontrolką ProductsDataSourceWithOptimisticConcurrency SqlDataSource dodaną w kroku pierwszym. Na koniec zaznacz opcje Włącz edytowanie i Włącz usuwanie z tagu inteligentnego.
Rysunek 6. Powiązanie kontrolki GridView z usługą SqlDataSource i włączanie edycji i usuwania (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Po dodaniu kontrolki GridView skonfiguruj jej wygląd, usuwając ProductID pole BoundField, zmieniając ProductName pole BoundField HeaderText na Product i aktualizując UnitPrice pole BoundField tak, aby jego HeaderText pole to po prostu Price. W idealnym przypadku ulepszyliśmy interfejs edycji, aby uwzględnić parametr RequiredFieldValidator dla ProductName wartości i parametr CompareValidator dla UnitPrice wartości (aby upewnić się, że jest to prawidłowo sformatowana wartość liczbowa). Zapoznaj się z samouczkiem Dotyczącym dostosowywania interfejsu modyfikacji danych , aby uzyskać bardziej szczegółowe informacje na temat dostosowywania interfejsu edytowania kontrolki GridView.
Uwaga / Notatka
Stan widoku kontrolki GridView musi być włączony, ponieważ oryginalne wartości przekazane z kontrolki GridView do usługi SqlDataSource są przechowywane w stanie widoku.
Po wprowadzeniu tych modyfikacji w GridView, znaczniki deklaratywne GridView i SqlDataSource powinny wyglądać podobnie do następujących:
<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>
Aby zobaczyć optymistyczne zarządzanie współbieżnością w działaniu, otwórz dwa okna przeglądarki i wczytaj stronę OptimisticConcurrency.aspx w obu. Kliknij przyciski Edytuj dla pierwszego produktu w obu przeglądarkach. W jednej przeglądarce zmień nazwę produktu i kliknij przycisk Aktualizuj. Przeglądarka wykona postback, a kontrolka GridView powróci do trybu sprzed edytowania, pokazując nową nazwę produktu dla właśnie edytowanego rekordu.
W drugim oknie przeglądarki zmień cenę (ale pozostaw nazwę produktu jako oryginalną wartość), a następnie kliknij przycisk Aktualizuj. Po ponownym przesłaniu, siatka powraca do trybu sprzed edycji, ale zmiana ceny nie jest rejestrowana. Druga przeglądarka wyświetla tę samą wartość co pierwsza nowa nazwa produktu ze starą ceną. Zmiany wprowadzone w drugim oknie przeglądarki zostały utracone. Co więcej, zmiany zniknęły bez większego rozgłosu, ponieważ nie było żadnego wyjątku ani komunikatu wskazującego, że właśnie doszło do naruszenia współbieżności.
Rysunek 7. Zmiany w drugim oknie przeglądarki zostały utracone w trybie dyskretnym (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Powodem, dla którego zmiany w drugiej przeglądarce nie zostały zatwierdzone, była klauzula UPDATE instrukcji WHERE, która odfiltrowała wszystkie rekordy i w związku z tym nie miała wpływu na żadne wiersze. Przyjrzyjmy się ponownie stwierdzeniu 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
Gdy drugie okno przeglądarki aktualizuje rekord, oryginalna nazwa produktu określona w WHERE klauzuli nie jest zgodna z istniejącą nazwą produktu (ponieważ została zmieniona przez pierwszą przeglądarkę). W związku z tym instrukcja [ProductName] = @original_ProductName zwraca wartość False i UPDATE nie ma wpływu na żadne rekordy.
Uwaga / Notatka
Usuwanie działa w ten sam sposób. Po otwarciu dwóch okien przeglądarki rozpocznij od edytowania danego produktu przy użyciu jednego, a następnie zapisania zmian. Po zapisaniu zmian w jednej przeglądarce kliknij przycisk Usuń dla tego samego produktu w drugiej. Ponieważ oryginalne wartości nie pasują do klauzuli DELETE w instrukcji WHERE, usunięcie kończy się cicho niepowodzeniem.
Z perspektywy użytkownika końcowego w drugim oknie przeglądarki po kliknięciu przycisku Aktualizuj siatka powróci do trybu wstępnej edycji, ale ich zmiany zostały utracone. Nie ma jednak żadnego wizualnego potwierdzenia, że ich zmiany nie zostały zastosowane. Idealnie, jeśli zmiany użytkownika zostaną utracone z powodu naruszenia współbieżności, powiadomimy ich i, być może, zachowalibyśmy siatkę w trybie edycji. Przyjrzyjmy się temu, jak to zrobić.
Krok 3. Określanie, kiedy wystąpiło naruszenie współbieżności
Ponieważ naruszenie współbieżności odrzuca wprowadzone zmiany, warto powiadomić użytkownika o wystąpieniu naruszenia współbieżności. Aby powiadomić użytkownika, dodajmy kontrolkę Etykieta Web na górze strony o nazwie ConcurrencyViolationMessage, której właściwość Text wyświetla następujący komunikat: Podjęto próbę zaktualizowania lub usunięcia rekordu, który został jednocześnie zaktualizowany przez innego użytkownika. Przejrzyj zmiany innego użytkownika, a następnie wykonaj ponownie aktualizację lub usuń. Ustaw właściwość kontrolki Etykieta CssClass na 'Ostrzeżenie', która jest klasą CSS zdefiniowaną w Styles.css, która wyświetla tekst w czerwonym kolorze, kursywą, pogrubieniem i dużą czcionką. Na koniec ustaw właściwości Etykiety Visible i EnableViewState na false. Spowoduje to ukrycie etykiety z wyjątkiem tych odsłonięć zwrotnych, w których jawnie ustawimy właściwość Visible na wartość true.
Rysunek 8. Dodawanie kontrolki Etykieta do strony w celu wyświetlenia ostrzeżenia (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Podczas przeprowadzania aktualizacji lub usuwania, procedury obsługi zdarzeń RowUpdated i RowDeleted kontrolki GridView są wykonywane po tym, jak kontrolka źródła danych zakończy żądaną aktualizację lub usunięcie. Możemy określić, ile wierszy miało wpływ na operację z tych procedur obsługi zdarzeń. Jeśli żadna liczba wierszy nie została zmieniona, chcemy wyświetlić etykietę ConcurrencyViolationMessage.
Utwórz procedurę obsługi zdarzeń dla zdarzeń RowUpdated i i RowDeleted i dodaj następujący kod:
protected void Products_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
if (e.AffectedRows == 0)
{
ConcurrencyViolationMessage.Visible = true;
e.KeepInEditMode = true;
// Rebind the data to the GridView to show the latest changes
Products.DataBind();
}
}
protected void Products_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
if (e.AffectedRows == 0)
ConcurrencyViolationMessage.Visible = true;
}
W obu programach obsługi zdarzeń sprawdzamy właściwość e.AffectedRows i, jeśli jest równa 0, ustawiamy właściwość ConcurrencyViolationMessage etykiety Visible na wartość true. W procedurze obsługi zdarzeń RowUpdated instruujemy również kontrolkę GridView, aby pozostawała w trybie edycji, ustawiając KeepInEditMode właściwość na true. W ten sposób musimy ponownie połączyć dane z siatką, aby inne dane użytkownika zostały załadowane do interfejsu edycji. Jest to realizowane przez wywołanie metody GridView.DataBind()
Jak pokazano na rysunku 9, z tymi dwoma procedurami obsługi zdarzeń jest wyświetlany bardzo zauważalny komunikat za każdym razem, gdy wystąpi naruszenie współbieżności.
Rysunek 9: Wyświetlana jest wiadomość przy próbie naruszenia współbieżności (kliknij, aby wyświetlić obraz w pełnym rozmiarze)
Podsumowanie
Podczas tworzenia aplikacji internetowej, w której wielu współbieżnych użytkowników może edytować te same dane, należy wziąć pod uwagę opcje kontroli współbieżności. Domyślnie, kontrolki danych sieci Web i kontrolki źródła danych ASP.NET nie korzystają z żadnych mechanizmów kontroli współbieżności. Jak pokazano w tym samouczku, implementacja optymistycznej kontroli współbieżności za pomocą usługi SqlDataSource jest stosunkowo szybka i łatwa. Usługa SqlDataSource obsługuje większość zadań związanych z dodawaniem rozszerzonych klauzul do automatycznie wygenerowanych instrukcji WHERE i UPDATE, ale istnieje kilka subtelności w obsłudze kolumn wartości DELETE, co jest omówione w sekcji Poprawne obsługiwanie wartości NULL.
Ten samouczek kończy badanie bazy danych SqlDataSource. Pozostałe samouczki powrócą do pracy z danymi przy użyciu obiektu ObjectDataSource i architektury warstwowej.
Szczęśliwe programowanie!
Informacje o autorze
Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można go uzyskać pod adresem mitchell@4GuysFromRolla.com.