Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
door Scott Mitchell
In deze zelfstudie bekijken we de essentiële aspecten van optimistisch gelijktijdigheidsbeheer en verkennen we vervolgens hoe u dit implementeert met behulp van het besturingselement SqlDataSource.
Introductie
In de voorgaande zelfstudie hebben we onderzocht hoe u mogelijkheden voor invoegen, bijwerken en verwijderen toevoegt aan het besturingselement SqlDataSource. Kortom, om deze functies te bieden moesten we de bijbehorende SQL-instructie in de eigenschappen van de besturingselementen INSERT, UPDATE, of DELETE opgeven, samen met de juiste parameters in de verzamelingen InsertCommand, UpdateCommand, en DeleteCommand. Hoewel deze eigenschappen en verzamelingen handmatig kunnen worden opgegeven, biedt de knop Geavanceerd configureren van de wizard Gegevensbron een selectievakje Genereren INSERTUPDATEen DELETE instructies waarmee deze instructies automatisch worden gemaakt op basis van de SELECT instructie.
Naast het selectievakje Genereren INSERT, UPDATE en DELETE instructies bevat het dialoogvenster Geavanceerde opties voor SQL-generatie een optie Gebruik maken van optimistische gelijktijdigheid (zie afbeelding 1). Wanneer deze optie is ingeschakeld, worden de WHERE componenten in de automatisch gegenereerde UPDATE en DELETE instructies gewijzigd om alleen de update uit te voeren of te verwijderen als de onderliggende databasegegevens niet zijn gewijzigd sinds de gebruiker de gegevens voor het laatst in het raster heeft geladen.
Afbeelding 1: U kunt optimistische gelijktijdigheidsondersteuning toevoegen vanuit het dialoogvenster Geavanceerde OPTIES voor SQL-generatie
In de zelfstudie Optimistische gelijktijdigheid implementeren hebben we de basisprincipes van optimistisch gelijktijdigheidsbeheer onderzocht en hoe u deze kunt toevoegen aan de ObjectDataSource. In deze zelfstudie herzien we de basisprincipes van optimistisch gelijktijdigheidsbeheer en verkennen we vervolgens hoe dit geïmplementeerd kan worden met behulp van de SqlDataSource.
Een samenvatting van optimistische gelijktijdigheid
Voor webtoepassingen waarmee meerdere, gelijktijdige gebruikers dezelfde gegevens kunnen bewerken of verwijderen, bestaat er een mogelijkheid dat een gebruiker per ongeluk een andere wijziging kan overschrijven. In de zelfstudie Optimistische gelijktijdigheid implementeren heb ik het volgende voorbeeld gegeven:
Stel dat twee gebruikers, Jisun en Sam, beide een pagina bezochten in een toepassing waarmee bezoekers producten konden bijwerken en verwijderen via een GridView-besturingselement. Beide klikken op de knop Bewerken voor Chai rond dezelfde tijd. Jisun wijzigt de productnaam in Chai Tea en klikt op de knop Bijwerken. Het nettoresultaat is een UPDATE instructie die naar de database wordt verzonden, waarmee alle bijwerkbare velden van het product worden ingesteld (zelfs als Jisun slechts één veld heeft bijgewerkt). ProductName Op dit moment heeft de database de waarden Chai Tea, de categorie Dranken, de leverancier Exotische Vloeistoffen, enzovoort voor dit specifieke product. In het scherm GridView op Sam s ziet u echter nog steeds de productnaam in de bewerkbare GridView-rij als Chai. Een paar seconden nadat Jisun's wijzigingen zijn doorgevoerd, werkt Sam de categorie bij naar Condiments en klikt u op Update. Dit resulteert in een UPDATE instructie die naar de database wordt verzonden waarmee de productnaam wordt ingesteld op Chai, de CategoryID bijbehorende categorie-id voor condiments, enzovoort. Jisun's wijzigingen in de productnaam zijn overschreven.
Afbeelding 2 illustreert deze interactie.
Afbeelding 2: Wanneer twee gebruikers tegelijk een record bijwerken, kunnen de wijzigingen van de ene gebruiker de andere overschrijven (klik om de volledige afbeelding weer te geven)
Om te voorkomen dat dit scenario wordt uitgevouwen, moet een vorm van gelijktijdigheidsbeheer worden geïmplementeerd. Optimistische gelijktijdigheid Deze zelfstudie richt zich op de veronderstelling dat er nu en dan gelijktijdigheidsconflicten kunnen zijn, maar dat dergelijke conflicten zich de overgrote meerderheid van de tijd niet voordoen. Als er een conflict optreedt, informeert optimistisch gelijktijdigheidsbeheer de gebruiker dat de wijzigingen niet kunnen worden opgeslagen omdat een andere gebruiker dezelfde gegevens heeft gewijzigd.
Opmerking
Voor toepassingen waarbij wordt aangenomen dat er veel gelijktijdigheidsconflicten zijn of als dergelijke conflicten niet acceptabel zijn, kan in plaats daarvan pessimistisch gelijktijdigheidsbeheer worden gebruikt. Raadpleeg de zelfstudie Optimistische gelijktijdigheid implementeren voor een uitgebreidere discussie over pessimistische gelijktijdigheidscontrole.
Optimistisch gelijktijdigheidsbeheer werkt door ervoor te zorgen dat de record die wordt bijgewerkt of verwijderd, dezelfde waarden heeft als bij het bijwerken of verwijderen van het proces. Wanneer u bijvoorbeeld op de knop Bewerken in een bewerkbare GridView klikt, worden de waarden van de records gelezen uit de database en weergegeven in tekstvakken en andere webbesturingselementen. Deze oorspronkelijke waarden worden opgeslagen door de GridView. Nadat de gebruiker later wijzigingen heeft aangebracht en op de knop Bijwerken heeft geklikt, moet de UPDATE gebruikte instructie rekening houden met de oorspronkelijke waarden plus de nieuwe waarden en alleen de onderliggende databaserecord bijwerken als de oorspronkelijke waarden die de gebruiker heeft bewerkt, identiek zijn aan de waarden die zich nog in de database bevinden. Afbeelding 3 geeft deze reeks gebeurtenissen weer.
Afbeelding 3: Als u wilt bijwerken of verwijderen, moeten de oorspronkelijke waarden gelijk zijn aan de huidige databasewaarden (klik om de volledige afbeelding weer te geven)
Er zijn verschillende benaderingen voor het implementeren van optimistische gelijktijdigheid (zie Peter A. Bromberg'sOptimistische logica voor gelijktijdigheid bijwerken voor een kort overzicht van een aantal opties). De techniek gebruikt door de SqlDataSource (en door de ADO.NET Typed DataSets die in onze Data Access-laag worden gebruikt) vergroot de WHERE clausule om een vergelijking te maken van alle oorspronkelijke waarden. Met de volgende UPDATE instructie wordt bijvoorbeeld alleen de naam en prijs van een product bijgewerkt als de huidige databasewaarden gelijk zijn aan de waarden die oorspronkelijk zijn opgehaald bij het bijwerken van de record in GridView. De @ProductName en @UnitPrice parameters bevatten de nieuwe waarden die door de gebruiker zijn ingevoerd, terwijl @original_ProductName ze @original_UnitPrice de waarden bevatten die oorspronkelijk in GridView zijn geladen toen op de knop Bewerken werd geklikt:
UPDATE Products SET
ProductName = @ProductName,
UnitPrice = @UnitPrice
WHERE
ProductID = @original_ProductID AND
ProductName = @original_ProductName AND
UnitPrice = @original_UnitPrice
Zoals we in deze zelfstudie zien, is het inschakelen van optimistisch gelijktijdigheidsbeheer met sqlDataSource net zo eenvoudig als het inschakelen van een selectievakje.
Stap 1: Een SqlDataSource maken die optimistische gelijktijdigheid ondersteunt
Open eerst de OptimisticConcurrency.aspx pagina vanuit de SqlDataSource map. Sleep een SqlDataSource-besturingselement van de Werkset naar de ontwerper, door de eigenschap ID in te stellen op ProductsDataSourceWithOptimisticConcurrency. Klik vervolgens op de koppeling Gegevensbron configureren vanuit het slimme label van het besturingselement. Kies in het eerste scherm van de wizard om met de NORTHWINDConnectionString te werken en klik op Volgende.
Afbeelding 4: Kiezen om met de NORTHWINDConnectionStringafbeelding te werken (klik om de afbeelding op volledige grootte weer te geven)
In dit voorbeeld voegen we een GridView toe waarmee gebruikers de Products tabel kunnen bewerken. Kies daarom in het scherm Het configureren van de Select Statement de Products tabel in de vervolgkeuzelijst en selecteer de ProductID, ProductName, UnitPrice en Discontinued kolommen, zoals wordt weergegeven in afbeelding 5.
Afbeelding 5: Uit de Products tabel de ProductID, ProductName, UnitPrice en Discontinued kolommen ophalen (Klik om de afbeelding op volledige grootte weer te geven)
Nadat u de kolommen hebt gekozen, klikt u op de knop Geavanceerd om het dialoogvenster Geavanceerde SQL-generatieopties weer te geven. Controleer de instructies voor Genereren INSERT, UPDATE, en DELETE, en gebruik de selectievakjes voor Optimistische gelijktijdigheid, klik vervolgens op OK (raadpleeg afbeelding 1 voor een schermopname). Voltooi de wizard door op Volgende en vervolgens Op Voltooien te klikken.
Nadat u de wizard Gegevensbron configureren hebt voltooid, neem even de tijd om de resulterende DeleteCommand en UpdateCommand eigenschappen en de DeleteParameters en UpdateParameters verzamelingen te bekijken. De eenvoudigste manier om dit te doen, is door op het tabblad Bron in de linkerbenedenhoek te klikken om de declaratieve syntaxis van de pagina weer te geven. Daar vindt u een UpdateCommand waarde van:
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
Met zeven parameters in de UpdateParameters verzameling:
<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>
Op dezelfde manier moeten de DeleteCommand eigenschappen en DeleteParameters verzameling er als volgt uitzien:
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>
Naast het uitbreiden van de WHERE clausules van de UpdateCommand en DeleteCommand eigenschappen (en het toevoegen van de aanvullende parameters aan de respectieve parametercollecties), past het selecteren van de optie Optimistische gelijktijdigheid gebruiken twee andere eigenschappen aan.
- Hiermee wijzigt u de
ConflictDetectioneigenschap vanOverwriteChanges(de standaardinstelling) inCompareAllValues - Wijzigt de
OldValuesParameterFormatStringeigenschap van {0} (de standaardinstelling) in original_{0} .
Wanneer het gegevensweb besturingselement de SqlDataSource-s Update() of Delete() -methode aanroept, worden de oorspronkelijke waarden doorgegeven. Als de eigenschap SqlDataSource ConflictDetection is ingesteld op CompareAllValues, worden deze oorspronkelijke waarden toegevoegd aan de opdracht. De OldValuesParameterFormatString eigenschap biedt het naamgevingspatroon dat wordt gebruikt voor deze oorspronkelijke waardeparameters. De wizard Gegevensbron configureren maakt gebruik van original_{0} en noemt elke oorspronkelijke parameter in de UpdateCommand eigenschappen DeleteCommand en verzamelingen UpdateParametersDeleteParameters dienovereenkomstig.
Opmerking
Omdat we de invoegmogelijkheden van de SqlDataSource control niet gebruiken, kunt u de InsertCommand eigenschap en de InsertParameters bijbehorende verzameling verwijderen.
Het correct verwerken vanNULLwaarden
Helaas werken de uitgebreide UPDATE en DELETE instructies, automatisch gegenereerd door de wizard Gegevensbron configureren, niet wanneer u optimistische gelijktijdigheid gebruikt met records die waarden bevatten. Bekijk onze SqlDataSource s UpdateCommandom te zien waarom:
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
De UnitPrice kolom in de Products tabel kan waarden bevatten NULL . Als een bepaalde record een NULL waarde voor UnitPriceheeft, wordt het WHERE componentgedeelte [UnitPrice] = @original_UnitPricealtijd geëvalueerd als Onwaar, omdat NULL = NULL altijd Onwaar wordt geretourneerd. Records die NULL-waarden bevatten, kunnen daarom niet worden bewerkt of verwijderd, omdat de UPDATE en DELETE uitspraken in de WHERE-clausules geen rijen retourneren om bij te werken of te verwijderen.
Opmerking
Deze fout is voor het eerst gerapporteerd aan Microsoft in juni 2004 in SqlDataSource genereert onjuiste SQL-instructies en wordt naar verwachting opgelost in de volgende versie van ASP.NET.
Om dit op te lossen, moeten we de WHERE-componenten in zowel de UpdateCommand- als de DeleteCommand-eigenschappen handmatig bijwerken voor alle kolommen die NULL waarden kunnen hebben. In het algemeen wijzigt u [ColumnName] = @original_ColumnName naar:
(
([ColumnName] IS NULL AND @original_ColumnName IS NULL)
OR
([ColumnName] = @original_ColumnName)
)
Deze wijziging kan rechtstreeks worden aangebracht via de declaratieve markeringen, via de opties UpdateQuery of DeleteQuery in het venster Eigenschappen, of via de tabbladen UPDATE en DELETE in de optie Een aangepaste SQL-instructie of opgeslagen procedure opgeven in de wizard Gegevensbron configureren. Deze wijziging moet ook worden aangebracht voor elke kolom in de UpdateCommand- en DeleteCommands-categorie WHERE die NULL-waarden kan bevatten.
Als we dit toepassen op ons voorbeeld, resulteren de volgende gewijzigde UpdateCommand en DeleteCommand waarden:
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
Stap 2: Een rasterweergave toevoegen met opties voor bewerken en verwijderen
Nu sqlDataSource is geconfigureerd ter ondersteuning van optimistische gelijktijdigheid, hoeft u alleen maar een gegevenswebbeheer toe te voegen aan de pagina die gebruikmaakt van dit gelijktijdigheidsbeheer. Voor deze zelfstudie gaan we een GridView toevoegen die zowel bewerkings- als verwijderfunctionaliteit biedt. Als u dit wilt doen, sleept u een GridView van de toolbox naar de Ontwerper en stelt u het in ID op Products. Bind deze vanuit de smart tag van de GridView aan het ProductsDataSourceWithOptimisticConcurrency SqlDataSource-besturingselement dat is toegevoegd in stap 1. Controleer ten slotte de opties Bewerken inschakelen en Verwijderen inschakelen vanuit het infolabel.
Afbeelding 6: Koppel de GridView aan de SqlDataSource en schakel bewerken en verwijderen in (klik om de volledige afbeelding weer te geven)
Nadat u de GridView hebt toegevoegd, configureert u het uiterlijk door het BoundField ProductID te verwijderen, de eigenschap van BoundField ProductName te wijzigen naar Product, en het BoundField HeaderText bij te werken, zodat de eigenschap UnitPrice gewoon Prijs is. Idealiter verbeteren we de bewerkingsinterface om een RequiredFieldValidator op te nemen voor de ProductName waarde en een CompareValidator voor de UnitPrice waarde (om ervoor te zorgen dat deze een correct opgemaakte numerieke waarde is). Raadpleeg de zelfstudie Over het aanpassen van de interface voor gegevenswijziging voor een uitgebreider overzicht van het aanpassen van de bewerkingsinterface van GridView.
Opmerking
De weergavestatus van GridView moet zijn ingeschakeld omdat de oorspronkelijke waarden die vanuit GridView aan de SqlDataSource worden doorgegeven, worden opgeslagen in de weergavestatus.
Nadat u deze wijzigingen aan de GridView hebt aangebracht, moeten de declaratieve markeringen van GridView en SqlDataSource er ongeveer als volgt uitzien:
<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>
Als u het optimistische gelijktijdigheidsbeheer in actie wilt zien, opent u twee browservensters en laadt u de OptimisticConcurrency.aspx pagina in beide vensters. Klik op de knoppen Bewerken voor het eerste product in beide browsers. Wijzig in één browser de productnaam en klik op Bijwerken. De browser voert een postback uit en de GridView keert terug naar de oorspronkelijke modus, met de nieuwe productnaam voor het record dat zojuist is bewerkt.
Wijzig in het tweede browservenster de prijs (maar laat de productnaam staan als oorspronkelijke waarde) en klik op Bijwerken. Bij terugzending keert het raster terug naar de prebewerkingsmodus, maar de wijziging in de prijs wordt niet vastgelegd. In de tweede browser wordt dezelfde waarde weergegeven als de eerste met de nieuwe productnaam met de oude prijs. De wijzigingen in het tweede browservenster zijn verloren gegaan. Bovendien zijn de wijzigingen nogal rustig verloren gegaan, omdat er geen uitzondering of bericht is dat er zojuist een gelijktijdigheidsfout is opgetreden.
Afbeelding 7: De wijzigingen in het tweede browservenster zijn op de achtergrond verloren gegaan (klik om de afbeelding op volledige grootte weer te geven)
De reden waarom de wijzigingen van de tweede browser niet zijn doorgevoerd, is omdat de UPDATEWHERE clausule alle records filterde en daarom geen invloed had op de rijen. Laten we de UPDATE instructie nog eens bekijken:
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
Wanneer in het tweede browservenster de record wordt bijgewerkt, komt de oorspronkelijke productnaam die is opgegeven in de WHERE component niet overeen met de bestaande productnaam (omdat deze is gewijzigd door de eerste browser). Daarom retourneert de instructie [ProductName] = @original_ProductName False en heeft dit UPDATE geen invloed op records.
Opmerking
Verwijderen werkt op dezelfde manier. Als er twee browservensters zijn geopend, begint u met het bewerken van een bepaald product met één en slaat u vervolgens de wijzigingen op. Nadat u de wijzigingen in de ene browser hebt opgeslagen, klikt u op de knop Verwijderen voor hetzelfde product in het andere. Omdat de oorspronkelijke waarden niet overeenkomen in de DELETE instructieclausule WHERE, mislukt het verwijderen stilletjes.
Vanuit het perspectief van de eindgebruiker in het tweede browservenster, nadat u op de knop Bijwerken hebt geklikt, keert het raster terug naar de modus voor prebewerking, maar zijn de wijzigingen verloren gegaan. Er is echter geen visuele feedback dat hun wijzigingen niet vastgelegd werden. Idealiter, als de wijzigingen van een gebruiker verloren gaan door een schending van gelijktijdigheid, zouden we ze op de hoogte stellen en mogelijk het raster in de bewerkingsmodus houden. Laten we eens kijken hoe u dit kunt doen.
Stap 3: bepalen wanneer er een gelijktijdigheidsfout is opgetreden
Aangezien een schending van gelijktijdigheid de wijzigingen weigert die u hebt aangebracht, is het handig om de gebruiker te waarschuwen wanneer er een schending van gelijktijdigheid is opgetreden. Als u de gebruiker wilt waarschuwen, voegt u een labelwebbesturingselement toe aan de bovenkant van de pagina met de naam ConcurrencyViolationMessage waarvan Text de eigenschap het volgende bericht weergeeft: U hebt geprobeerd een record bij te werken of te verwijderen die tegelijkertijd door een andere gebruiker is bijgewerkt. Controleer de wijzigingen van de andere gebruiker en voer de update opnieuw uit of verwijder deze. Stel de eigenschap van het Label-besturingselement CssClass in op Waarschuwing, een CSS-klasse die is gedefinieerd in Styles.css en de tekst weergeeft in een groot, rood, cursief en vet lettertype. Stel ten slotte de labels Visible en EnableViewState eigenschappen in op False. Hiermee wordt het label verborgen, behalve die postbacks waarop we expliciet de Visible eigenschap op True hebben ingesteld.
Afbeelding 8: Voeg een labelbesturingselement toe aan de pagina om de waarschuwing weer te geven (klik om de afbeelding op volledige grootte weer te geven)
Wanneer u een update uitvoert of verwijdert, worden de GridView's RowUpdated en RowDeleted gebeurtenishandlers geactiveerd nadat het besturingselement voor de gegevensbron de aangevraagde update of verwijdering heeft uitgevoerd. Door deze eventhandlers kunnen we bepalen hoeveel rijen door de operatie zijn beïnvloed. Als er geen rijen zijn beïnvloed, willen we het ConcurrencyViolationMessage label weergeven.
Maak een gebeurtenis-handler voor zowel de RowUpdated als de RowDeleted gebeurtenissen en voeg de volgende code toe.
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
In beide gebeurtenis-handlers controleren we de e.AffectedRows eigenschap en, als deze gelijk is aan 0, stelt u de ConcurrencyViolationMessage eigenschap Label s Visible in op True. In de RowUpdated gebeurtenis-handler geven we ook de GridView de opdracht om in de bewerkingsmodus te blijven door de KeepInEditMode eigenschap in te stellen op true. Hierbij moeten we de gegevens opnieuw koppelen aan het raster, zodat de andere gebruikersgegevens in de bewerkingsinterface worden geladen. Dit wordt bereikt door de methode GridView DataBind() aan te roepen.
Zoals in afbeelding 9 wordt weergegeven, wordt bij deze twee gebeurtenis-handlers een zeer merkbaar bericht weergegeven wanneer er sprake is van een schending van gelijktijdigheid.
Afbeelding 9: Er wordt een bericht weergegeven bij een concurrentieschending (klik om de afbeelding op volledige grootte weer te geven)
Samenvatting
Wanneer u een webtoepassing maakt waarbij meerdere gelijktijdige gebruikers dezelfde gegevens kunnen bewerken, is het belangrijk om gelijktijdigheidsbeheeropties te overwegen. De ASP.NET gegevenswebbesturingselementen en besturingselementen voor gegevensbronnen maken standaard geen gebruik van gelijktijdigheidsbeheer. Zoals we in deze zelfstudie hebben gezien, is het implementeren van optimistisch gelijktijdigheidsbeheer met sqlDataSource relatief snel en eenvoudig. De SqlDataSource handelt het grootste deel van het voorbereidend werk af voor het toevoegen van uitgebreide WHERE clausules aan de automatisch gegenereerde UPDATE en DELETE instructies, maar er zijn enkele subtiliteiten bij het verwerken van NULL waardekolommen, zoals besproken in de sectie Correct omgaan met NULL waarden.
In deze handleiding wordt ons onderzoek naar de SqlDataSource afgerond. Onze overgebleven handleidingen zullen zich weer richten op gegevensverwerking met behulp van de ObjectDataSource en een gelaagde architectuur.
Veel plezier met programmeren!
Over de auteur
Scott Mitchell, auteur van zeven ASP/ASP.NET-boeken en oprichter van 4GuysFromRolla.com, werkt sinds 1998 met Microsoft-webtechnologieën. Scott werkt als onafhankelijk consultant, trainer en schrijver. Zijn laatste boek is Sams Teach Yourself ASP.NET 2.0 in 24 uur. Hij kan worden bereikt op mitchell@4GuysFromRolla.com.