Implementowanie optymistycznej współbieżności przy użyciu kontrolki SqlDataSource (C#)

Autor: Scott Mitchell

Pobierz plik PDF

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 zapewnić te funkcje, musieliśmy określić odpowiednią INSERTinstrukcję , UPDATElub DELETE SQL w kontrolce s InsertCommand, UpdateCommandlub DeleteCommand właściwości wraz z odpowiednimi parametrami w InsertParametersUpdateParameterskolekcjach , i DeleteParameters . Chociaż te właściwości i kolekcje można określić ręcznie, przycisk Zaawansowane Kreatora konfigurowania źródła danych oferuje pole wyboru Generuj INSERTinstrukcje , UPDATEi DELETE , które automatycznie utworzy te instrukcje na SELECT podstawie instrukcji .

Wraz z polem wyboru Generuj INSERTinstrukcje , UPDATEi DELETE okno dialogowe Zaawansowane opcje generowania SQL zawiera opcję Użyj optymistycznej współbieżności (zobacz Rysunek 1). Po sprawdzeniu klauzule w automatycznie wygenerowanych UPDATE instrukcjach i DELETE są modyfikowane w celu przeprowadzenia aktualizacji lub usunięcia tylko wtedy, WHERE gdy bazowe dane bazy danych nie zostały zmodyfikowane od czasu ostatniego załadowania danych przez użytkownika do siatki.

Możesz dodać optymistyczną obsługę współbieżności z okna dialogowego Zaawansowane opcje generowania SQL

Rysunek 1. Możesz dodać optymistyczną obsługę współbieżności z okna dialogowego Zaawansowane opcje generowania SQL

W samouczku 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 samouczku omówimy podstawy optymistycznej kontrolki współbieżności, a następnie dowiesz się, jak zaimplementować ją przy użyciu usługi 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 samouczku Implementowanie optymistycznej współbieżności podano 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 kliknij przycisk Edytuj dla chai mniej więcej w tym samym czasie. Jisun zmienia nazwę produktu na Chai Tea i klika przycisk Aktualizuj. Wynikiem net jest UPDATE instrukcja, która jest wysyłana do bazy danych, która ustawia wszystkie pola z możliwością aktualizacji produktu (mimo że Jisun zaktualizował 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 na ekranie GridView na ekranie Sam nadal wyświetlana jest nazwa produktu w edytowalnym wierszu GridView jako Chai. Kilka sekund po zatwierdzeniu zmian programu Jisun sam aktualizuje kategorię na Condiments i klika pozycję Aktualizuj. UPDATE Spowoduje to wysłanie instrukcji do bazy danych, która ustawia nazwę produktu na Chai, CategoryID na odpowiadający identyfikator kategorii Condiments itd. Zmiany w nazwie produktu jisun zostały zastąpione.

Rysunek 2 ilustruje tę interakcję.

Gdy dwóch użytkowników jednocześnie zaktualizuje rekord, istnieje możliwość zmiany jednego użytkownika w celu zastąpienia drugiego

Rysunek 2. Gdy dwóch użytkowników jednocześnie zaktualizuje rekord, istnieje możliwość zmiany jednego użytkownika w celu zastąpienia drugiego (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Aby zapobiec rozwojowi tego scenariusza, należy zaimplementować formę kontrolki współbieżności . Optymistyczna współbieżność skupiona na tym samouczku działa na założeniu, że chociaż konflikty współbieżności mogą występować co chwilę, 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 ich zmiany nie można zapisać, ponieważ inny użytkownik zmodyfikował te same dane.

Uwaga

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 kontrolki współbieżności. Zapoznaj się z samouczkiem Implementowanie 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 edytowalnym elemecie GridView wartości rekordów są odczytywane z bazy danych i wyświetlane w polach TextBoxes i innych kontrolkach sieci Web. Te oryginalne wartości są zapisywane przez element GridView. Później, gdy użytkownik wprowadza zmiany i klika przycisk Aktualizuj, UPDATE użyta instrukcja musi uwzględniać oryginalne wartości oraz nowe wartości i aktualizować tylko bazowy rekord bazy danych, jeśli oryginalne wartości, które użytkownik zaczął edytować, są identyczne z wartościami nadal w bazie danych. Rysunek 3 przedstawia tę sekwencję zdarzeń.

Aby aktualizacja lub usunięcie powiodło się, oryginalne wartości muszą być równe bieżącym wartościom bazy danych

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 przez zestawy danych typu ADO.NET używanych w warstwie dostępu do danych) rozszerza WHERE klauzulę, aby uwzględnić porównanie wszystkich oryginalnych wartości. Poniższa UPDATE instrukcja aktualizuje na przykład 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 aktualizowania rekordu w elemencie GridView. 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 kontrolki współbieżności z usługą SqlDataSource jest tak proste, jak zaznaczenie pola wyboru.

Krok 1. Tworzenie bazy danych SqlDataSource obsługującej optymistyczną współbieżność

Zacznij od otwarcia OptimisticConcurrency.aspx strony z SqlDataSource folderu. Przeciągnij kontrolkę SqlDataSource z przybornika na Projektant, a następnie ustaw jej ID właściwość 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.

Wybierz opcję Pracy z elementem NORTHWINDConnectionString

Rysunek 4. Wybierz opcję Pracy z (NORTHWINDConnectionStringkliknij, aby wyświetlić obraz pełnowymiarowy)

W tym przykładzie dodamy element GridView, który umożliwia użytkownikom edytowanie Products tabeli. W związku z tym na ekranie Konfigurowanie instrukcji Select wybierz Products tabelę z listy rozwijanej i wybierz ProductIDkolumny , , UnitPriceProductNameiDiscontinued, jak pokazano na rysunku 5.

Z tabeli Products Zwróć kolumny ProductID, ProductName, UnitPrice i Discontinued

Rysunek 5. Z Products tabeli zwróć ProductIDkolumny , 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 INSERTinstrukcje , UPDATEi DELETE Użyj optymistycznej współbieżności, a następnie kliknij przycisk OK (zapoznaj się z rysunkiem 1 na zrzucie ekranu). Ukończ pracę kreatora, klikając przycisk Dalej, a następnie zakończ.

Po ukończeniu pracy Kreatora konfigurowania źródła danych poświęć chwilę, aby sprawdzić wynikowe DeleteCommand właściwości i UpdateCommand kolekcje i DeleteParameters .UpdateParameters Najprostszym sposobem, aby to zrobić, jest kliknięcie karty Źródło w lewym dolnym rogu, aby wyświetlić składnię deklaracyjną strony. W tym miejscu znajdziesz UpdateCommand wartość:

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 siedmiu parametrów 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 właściwość i DeleteParameters kolekcja powinny wyglądać następującoDeleteCommand:

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 WHERE klauzul UpdateCommand właściwości i DeleteCommand (i dodawania dodatkowych parametrów do odpowiednich kolekcji parametrów), wybranie opcji Użyj optymistycznej współbieżności dostosowuje dwie inne właściwości:

Gdy kontrolka internetowa danych wywołuje metodę SqlDataSource lub Update()Delete() , przekazuje oryginalne wartości. Jeśli właściwość SqlDataSource jest ustawiona ConflictDetection na CompareAllValues, te oryginalne wartości zostaną dodane do polecenia . 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 we UpdateCommand właściwościach i DeleteCommand kolekcjach oraz UpdateParameters odpowiednio DeleteParameters .

Uwaga

Ponieważ nie używamy możliwości wstawiania kontrolki SqlDataSource, możesz usunąć InsertCommand właściwość i jej InsertParameters kolekcję.

Poprawne obsługaNULLwartości

Niestety rozszerzone UPDATE instrukcje i DELETE automatycznie generowane przez Kreatora konfigurowania źródła danych w przypadku korzystania z optymistycznej współbieżności nie działają z rekordami zawierającymi NULL wartości. Aby zobaczyć, dlaczego warto rozważyć nasze źródło danych 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

Kolumna UnitPriceProducts w tabeli może zawierać NULL wartości. Jeśli określony rekord ma NULL wartość , UnitPriceWHERE część [UnitPrice] = @original_UnitPrice klauzuli zawsze będzie oceniać wartość False, ponieważ NULL = NULL zawsze zwraca wartość False. W związku z tym rekordy zawierające NULL wartości nie mogą być edytowane ani usuwane, ponieważ UPDATE klauzule and DELETEWHERE nie będą zwracać żadnych wierszy do aktualizacji ani usunięcia.

Uwaga

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ć WHERE klauzule zarówno we właściwościach, jak UpdateCommand i DeleteCommand dla wszystkich kolumn, które mogą mieć NULL wartości. 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 z okno Właściwości lub za pomocą kart UPDATE i DELETE w opcji Określ niestandardową instrukcję SQL lub procedurę składowaną w kreatorze Konfigurowanie źródła danych. Ponownie należy wprowadzić tę modyfikację dla każdej kolumny w klauzuli UpdateCommand i WHEREDeleteCommand, która może zawierać NULL wartości.

Zastosowanie tej funkcji do naszego przykładu powoduje zmodyfikowanie następujących UpdateCommand wartości i 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

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 funkcje edytowania, jak i usuwania. Aby to osiągnąć, przeciągnij element GridView z przybornika na Projektant i ustaw go ID na Productswartość . Z tagu inteligentnego GridView powiąż go z kontrolką ProductsDataSourceWithOptimisticConcurrency SqlDataSource dodaną w kroku 1. Na koniec zaznacz opcje Włącz edytowanie i Włącz usuwanie z tagu inteligentnego.

Powiąż element GridView z usługą SqlDataSource i włącz edytowanie i usuwanie

Rysunek 6. Powiązanie widoku GridView z usługą SqlDataSource i włączanie edycji i usuwania (kliknij, aby wyświetlić obraz pełnowymiarowy)

Po dodaniu obiektu GridView skonfiguruj jego wygląd, usuwając ProductID właściwość BoundField, zmieniając ProductName właściwość BoundField HeaderText na Product i aktualizując UnitPrice pole BoundField tak, aby jej HeaderText właściwość to po prostu Price. W idealnym przypadku rozszerzyliśmy interfejs edycji tak, aby zawierał element 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 Dostosowywanie interfejsu modyfikacji danych , aby uzyskać bardziej szczegółowe informacje na temat dostosowywania interfejsu edycji kontrolki GridView.

Uwaga

Stan widoku kontrolki GridView musi być włączony, ponieważ oryginalne wartości przekazane z obiektu GridView do elementu SqlDataSource są przechowywane w stanie widoku.

Po wprowadzeniu tych modyfikacji w elementy 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ć optymistyczną kontrolę współbieżności w działaniu, otwórz dwa okna przeglądarki i załaduj OptimisticConcurrency.aspx stronę 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 zostanie zwrócona, a kontrolka GridView powróci do trybu przed edycją, pokazując nową nazwę produktu dla rekordu, który został właśnie edytowany.

W drugim oknie przeglądarki zmień cenę (ale pozostaw nazwę produktu jako oryginalną wartość) i kliknij przycisk Aktualizuj. Po powrocie siatka powraca do trybu przed edycją, ale zmiana ceny nie jest rejestrowana. Druga przeglądarka wyświetla taką samą wartość jak pierwsza nowa nazwa produktu ze starą ceną. Zmiany wprowadzone w drugim oknie przeglądarki zostały utracone. Ponadto zmiany zostały utracone dość cicho, ponieważ nie było wyjątku ani komunikatu wskazującego, że właśnie doszło do naruszenia współbieżności.

Zmiany w drugim oknie przeglądarki zostały utracone w trybie dyskretnym

Rysunek 7. Zmiany w drugim oknie przeglądarki zostały utracone w trybie dyskretnym (kliknij, aby wyświetlić obraz pełnowymiarowy)

Powodem, dla którego zmiany drugiej przeglądarki nie zostały zatwierdzone, było to, że UPDATE klauzula s WHERE instrukcji odfiltrowała wszystkie rekordy i w związku z tym nie miała wpływu na żadne wiersze. Ponownie przyjrzyjmy się instrukcji 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

Usuwanie działa w taki 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 s WHERE instrukcjiDELETE, usuwanie w trybie dyskretnym kończy się niepowodzeniem.

Z perspektywy użytkownika końcowego w drugim oknie przeglądarki po kliknięciu przycisku Aktualizuj siatka powróci do trybu przed edycją, ale ich zmiany zostały utracone. Nie ma jednak żadnych wizualnych opinii, że ich zmiany nie utkną. W idealnym przypadku, jeśli zmiany użytkownika zostaną utracone z naruszeniem współbieżności, powiadomimy ich i, być może, zachowaj siatkę w trybie edycji. Przyjrzyjmy się temu, jak to osiągnąć.

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 zaalarmować użytkownika, dodajmy kontrolkę Sieć Web etykiet w górnej części strony o nazwie ConcurrencyViolationMessage , której Text właściwość 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 ponów aktualizację lub usuń. Ustaw właściwość kontrolki Etykieta CssClass na Ostrzeżenie, która jest klasą CSS zdefiniowaną w Styles.css języku , która wyświetla tekst na czerwono, kursywę, pogrubienie i dużą czcionkę. Na koniec ustaw właściwość Etykieta Visible i EnableViewState na falsewartość . Spowoduje to ukrycie etykiety z wyjątkiem tylko tych ogłaszania zwrotnego, w których jawnie ustawimy jej Visible właściwość na truewartość .

Dodawanie kontrolki Etykieta do strony w celu wyświetlenia ostrzeżenia

Rysunek 8. Dodawanie kontrolki etykiety do strony w celu wyświetlenia ostrzeżenia (kliknij, aby wyświetlić obraz pełnowymiarowy)

Podczas przeprowadzania aktualizacji lub usuwania programy obsługi zdarzeń GridView RowUpdatedRowDeleted uruchamiane po wykonaniu żądanej aktualizacji lub usunięcia kontroli źródła danych. Możemy określić, ile wierszy wpłynęło na operację z tych procedur obsługi zdarzeń. Jeśli nie ma to wpływu na zero wierszy, 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 e.AffectedRows właściwość , a jeśli jest równa 0, ustaw ConcurrencyViolationMessage właściwość Etykieta Visible na truewartość . W procedurze obsługi zdarzeń RowUpdated instruujemy również obiekt GridView, aby pozostał 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, przy użyciu tych dwóch procedur obsługi zdarzeń jest wyświetlany bardzo zauważalny komunikat przy każdym wystąpieniu naruszenia współbieżności.

Komunikat jest wyświetlany na twarzy naruszenia współbieżności

Rysunek 9. Komunikat jest wyświetlany na twarzy 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 sieci Web i źródła danych ASP.NET nie korzystają z żadnej kontrolki 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. Element SqlDataSource obsługuje większość prac związanych z dodawaniem klauzul rozszerzonych WHERE do automatycznie wygenerowanych UPDATE instrukcji i DELETE , ale istnieje kilka subtelności obsługi NULL kolumn wartości, jak opisano w sekcji Poprawnie obsługiwane NULL wartości.

Ten samouczek kończy badanie elementu 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 do niego dotrzeć pod adresem mitchell@4GuysFromRolla.com. Lub za pośrednictwem swojego bloga, który można znaleźć na stronie http://ScottOnWriting.NET.