Implementieren von optimistischer Parallelität mit dem SqlDataSource-Steuerelement (C#)
von Scott Mitchell
In diesem Tutorial untersuchen wir die Grundlagen der Steuerung für optimistische Parallelität und untersuchen dann, wie sie mithilfe des SqlDataSource-Steuerelements implementiert werden kann.
Einführung
Im vorherigen Tutorial haben wir untersucht, wie Sie dem SqlDataSource-Steuerelement Funktionen zum Einfügen, Aktualisieren und Löschen hinzufügen. Kurz gesagt, um diese Features bereitzustellen, mussten wir die entsprechende INSERT
, - oder DELETE
SQL-Anweisung in den Steuerelementeigenschaften s InsertCommand
, UpdateCommand
oder DeleteCommand
sowie die entsprechenden Parameter in den InsertParameters
Auflistungen , UpdateParameters
und DeleteParameters
angeben. UPDATE
Während diese Eigenschaften und Auflistungen manuell angegeben werden können, bietet die Schaltfläche "Datenquellen konfigurieren" des Assistenten "Erweitert" das Kontrollkästchen "Anweisungen generierenINSERT
UPDATE
DELETE
", mit dem diese Anweisungen automatisch basierend auf der SELECT
-Anweisung erstellt werden.
Zusammen mit dem Kontrollkästchen Anweisungen generieren INSERT
, UPDATE
und DELETE
enthält das Dialogfeld Erweiterte SQL-Generierungsoptionen die Option Optimistische Parallelität verwenden (siehe Abbildung 1). Wenn dies aktiviert ist, werden die WHERE
Klauseln in der automatisch generierten UPDATE
und DELETE
-Anweisung so geändert, dass sie nur dann aktualisiert oder gelöscht werden, wenn die zugrunde liegenden Datenbankdaten nicht geändert wurden, seit der Benutzer die Daten zuletzt in das Raster geladen hat.
Abbildung 1: Sie können die Unterstützung für optimistische Parallelität über das Dialogfeld Erweiterte SQL-Generierungsoptionen hinzufügen.
Im Tutorial Implementieren von optimistischer Parallelität haben wir die Grundlagen des Steuerelements für optimistische Parallelität untersucht und wie sie der ObjectDataSource hinzugefügt wird. In diesem Tutorial retuschieren wir die grundlagen der Kontrolle der optimistischen Parallelität und untersuchen dann, wie sie mithilfe der SqlDataSource implementiert werden kann.
Eine Zusammenfassung der optimistischen Parallelität
Bei Webanwendungen, die es mehreren gleichzeitigen Benutzern ermöglichen, dieselben Daten zu bearbeiten oder zu löschen, besteht die Möglichkeit, dass ein Benutzer versehentlich änderungen eines anderen überschreibt. Im Tutorial Implementieren optimistischer Parallelität habe ich das folgende Beispiel angegeben:
Stellen Sie sich vor, zwei Benutzer, Jisun und Sam, besuchten beide eine Seite in einer Anwendung, die es Besuchern ermöglichte, Produkte über ein GridView-Steuerelement zu aktualisieren und zu löschen. Beide klicken ungefähr zur gleichen Zeit auf die Schaltfläche Bearbeiten für Chai. Jisun ändert den Produktnamen in Chai Tea und klickt auf die Schaltfläche Aktualisieren. Das Nettoergebnis ist eine UPDATE
Anweisung, die an die Datenbank gesendet wird, die alle aktualisierbaren Felder des Produkts festlegt (obwohl Jisun nur ein Feld aktualisiert hat, ProductName
). Zu diesem Zeitpunkt hat die Datenbank die Werte Chai Tea, die Kategorie Getränke, der Lieferant Exotic Liquids usw. für dieses spezielle Produkt. Der Bildschirm GridView auf Sam zeigt jedoch weiterhin den Produktnamen in der bearbeitbaren GridView-Zeile als Chai an. Einige Sekunden nach dem Commit von Jisuns Änderungen aktualisiert Sam die Kategorie in Condiments und klickt auf Aktualisieren. Dies führt zu einer UPDATE
an die Datenbank gesendeten Anweisung, die den Produktnamen auf Chai, die auf die CategoryID
entsprechende Condiments-Kategorie-ID usw. festlegt. Jisuns Änderungen am Produktnamen wurden überschrieben.
Abbildung 2 veranschaulicht diese Interaktion.
Abbildung 2: Wenn zwei Benutzer gleichzeitig einen Datensatz aktualisieren, besteht die Möglichkeit, dass die Änderungen eines Benutzers den anderen überschreiben (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Damit sich dieses Szenario nicht entfaltet, muss eine Form der Parallelitätssteuerung implementiert werden. Optimistische Parallelität Der Fokus dieses Tutorials basiert auf der Annahme, dass es zwar hin und wieder zu Parallelitätskonflikten kommen kann, aber in der überwiegenden Mehrheit der Zeit solche Konflikte nicht auftreten. Wenn also ein Konflikt auftritt, informiert die optimistische Parallelitätssteuerung den Benutzer einfach darüber, dass seine Änderungen nicht gespeichert werden können, da ein anderer Benutzer dieselben Daten geändert hat.
Hinweis
Für Anwendungen, bei denen davon ausgegangen wird, dass es viele Parallelitätskonflikte gibt oder wenn solche Konflikte nicht tolerierbar sind, kann stattdessen die pessimistische Parallelitätssteuerung verwendet werden. Im Tutorial Implementieren optimistischer Parallelität finden Sie eine ausführlichere Diskussion über pessimistische Parallelitätssteuerung.
Die optimistische Parallelitätssteuerung funktioniert, indem sichergestellt wird, dass der zu aktualisierende oder gelöschte Datensatz die gleichen Werte aufweist wie beim Starten des Aktualisierungs- oder Löschvorgangs. Wenn Sie beispielsweise in einer bearbeitbaren GridView auf die Schaltfläche Bearbeiten klicken, werden die Werte des Datensatzes aus der Datenbank gelesen und in TextBoxes und anderen Websteuerelementen angezeigt. Diese ursprünglichen Werte werden von GridView gespeichert. Später, nachdem der Benutzer seine Änderungen vorgenommen und auf die Schaltfläche Aktualisieren klickt, muss die UPDATE
verwendete Anweisung die ursprünglichen Werte plus die neuen Werte berücksichtigen und den zugrunde liegenden Datenbankdatensatz nur aktualisieren, wenn die ursprünglichen Werte, die der Benutzer bearbeitet hat, mit den Werten identisch sind, die sich noch in der Datenbank befinden. Abbildung 3 zeigt diese Ereignissequenz.
Abbildung 3: Damit das Update oder Löschen erfolgreich ist, müssen die ursprünglichen Werte den aktuellen Datenbankwerten entsprechen (Klicken Sie hier, um das bild in voller Größe anzuzeigen).
Es gibt verschiedene Ansätze, um optimistische Parallelität zu implementieren (siehe Peter A. BrombergsOptimistische Parallelitätsaktualisierungslogik für einen kurzen Blick auf eine Reihe von Optionen). Die von sqlDataSource (sowie von den in unserer Datenzugriffsebene verwendete ADO.NET Typisierte DataSets) erweitert die WHERE
Klausel, um einen Vergleich aller ursprünglichen Werte aufzunehmen. Die folgende UPDATE
Anweisung aktualisiert beispielsweise den Namen und den Preis eines Produkts nur, wenn die aktuellen Datenbankwerte den Werten entsprechen, die beim Aktualisieren des Datensatzes in GridView ursprünglich abgerufen wurden. Die @ProductName
Parameter und @UnitPrice
enthalten die vom Benutzer eingegebenen neuen Werte, während @original_ProductName
und @original_UnitPrice
die Werte enthalten, die ursprünglich in die GridView geladen wurden, als auf die Schaltfläche Bearbeiten geklickt wurde:
UPDATE Products SET
ProductName = @ProductName,
UnitPrice = @UnitPrice
WHERE
ProductID = @original_ProductID AND
ProductName = @original_ProductName AND
UnitPrice = @original_UnitPrice
Wie wir in diesem Tutorial sehen werden, ist das Aktivieren einer optimistischen Parallelitätssteuerung mit sqlDataSource so einfach wie das Aktivieren eines Kontrollkästchens.
Schritt 1: Erstellen einer SqlDataSource, die optimistische Parallelität unterstützt
Öffnen Sie zunächst die OptimisticConcurrency.aspx
Seite aus dem SqlDataSource
Ordner. Ziehen Sie ein SqlDataSource-Steuerelement aus der Toolbox auf die Designer, und legen Sie seine ID
Eigenschaft auf festProductsDataSourceWithOptimisticConcurrency
. Klicken Sie als Nächstes im Smarttag des Steuerelements auf den Link Datenquelle konfigurieren. Wählen Sie auf dem ersten Bildschirm im Assistenten aus, mit dem NORTHWINDConnectionString
zu arbeiten, und klicken Sie auf Weiter.
Abbildung 4: Wählen Sie aus, mit dem zu arbeiten (Klicken Sie hier, um dasNORTHWINDConnectionString
bild in voller Größe anzuzeigen)
In diesem Beispiel fügen wir eine GridView hinzu, mit der Benutzer die Products
Tabelle bearbeiten können. Wählen Sie daher auf dem Bildschirm Select-Anweisung konfigurieren die Products
Tabelle aus der Dropdownliste aus, und wählen Sie die ProductID
Spalten , ProductName
, UnitPrice
und Discontinued
aus, wie in Abbildung 5 dargestellt.
Abbildung 5: Geben Sie in der Products
Tabelle die ProductID
Spalten , ProductName
, , UnitPrice
und Discontinued
zurück (Klicken Sie, um das bild in voller Größe anzuzeigen)
Klicken Sie nach dem Auswählen der Spalten auf die Schaltfläche Erweitert, um das Dialogfeld Erweiterte SQL-Generierungsoptionen zu öffnen. Aktivieren Sie die Kontrollkästchen Anweisungen generierenINSERT
UPDATE
, , und DELETE
verwenden Sie optimistische Parallelität, und klicken Sie auf OK (Screenshot finden Sie zurück zu Abbildung 1). Schließen Sie den Assistenten ab, indem Sie auf Weiter und dann auf Fertig stellen klicken.
Nehmen Sie sich nach Abschluss des Assistenten Datenquellen konfigurieren einen Moment Zeit, um die resultierenden DeleteCommand
Eigenschaften und UpdateCommand
die DeleteParameters
Auflistungen und UpdateParameters
zu untersuchen. Am einfachsten können Sie dazu auf die Registerkarte Quelle in der unteren linken Ecke klicken, um die deklarative Syntax der Seite anzuzeigen. Dort finden Sie einen UpdateCommand
Wert von:
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
Mit sieben Parametern in der UpdateParameters
Auflistung:
<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>
In ähnlicher Weise sollten die DeleteCommand
Eigenschaft und DeleteParameters
Auflistung wie folgt aussehen:
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>
Zusätzlich zum Erweitern der WHERE
Klauseln der UpdateCommand
Eigenschaften und DeleteCommand
(und hinzufügen der zusätzlichen Parameter zu den jeweiligen Parametersammlungen) werden durch Auswählen der Option Optimistische Parallelität verwenden zwei weitere Eigenschaften angepasst:
- Ändert die
ConflictDetection
Eigenschaft vonOverwriteChanges
(Standard) inCompareAllValues
- Ändert die
OldValuesParameterFormatString
-Eigenschaft von {0} (Standard) in original_{0} .
Wenn das Datenwebsteuerelement die SqlDataSource-Methode Update()
oder Delete()
-Methode aufruft, werden die ursprünglichen Werte übergeben. Wenn die SqlDataSource-Eigenschaft ConflictDetection
auf CompareAllValues
festgelegt ist, werden diese ursprünglichen Werte dem Befehl hinzugefügt. Die OldValuesParameterFormatString
-Eigenschaft stellt das Benennungsmuster bereit, das für diese ursprünglichen Wertparameter verwendet wird. Der Assistent Datenquellen konfigurieren verwendet original_{0} und benennt jeden ursprünglichen Parameter in den UpdateCommand
Eigenschaften und DeleteCommand
und UpdateParameters
DeleteParameters
Auflistungen entsprechend.
Hinweis
Da wir die Einfügefunktionen des SqlDataSource-Steuerelements nicht verwenden, können Sie die Eigenschaft und ihre InsertCommand
InsertParameters
Auflistung entfernen.
Korrekte Verarbeitung vonNULL
Werten
Leider funktionieren die vom Assistenten Datenquellen konfigurieren automatisch generierten UPDATE
DELETE
erweiterten und -Anweisungen bei verwendung von optimistischer Parallelität nicht mit Datensätzen, die Werte enthalten NULL
. Um zu sehen, warum, sehen Sie sich unsere SqlDataSource an 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
Die UnitPrice
Spalte in der Products
Tabelle kann Werte aufweisen NULL
. Wenn ein bestimmter Datensatz über einen NULL
Wert für UnitPrice
verfügt, wird der WHERE
Klauselteil [UnitPrice] = @original_UnitPrice
immer auf False ausgewertet, da NULL = NULL
immer False zurückgegeben wird. Daher können Datensätze, die Werte enthalten NULL
, nicht bearbeitet oder gelöscht werden, da die UPDATE
- und DELETE
-Anweisungsklauseln WHERE
keine Zeilen zurückgeben, die aktualisiert oder gelöscht werden sollen.
Hinweis
Dieser Fehler wurde erstmals im Juni 2004 an Microsoft in SqlDataSource generiert falsche SQL-Anweisungen gemeldet und soll in der nächsten Version von ASP.NET behoben werden.
Um dies zu beheben, müssen wir die Klauseln in den WHERE
Eigenschaften und DeleteCommand
für alle Spalten, die UpdateCommand
Werte enthalten NULL
können, manuell aktualisieren. Wechseln Sie [ColumnName] = @original_ColumnName
im Allgemeinen zu:
(
([ColumnName] IS NULL AND @original_ColumnName IS NULL)
OR
([ColumnName] = @original_ColumnName)
)
Diese Änderung kann direkt über das deklarative Markup, über die Optionen UpdateQuery oder DeleteQuery aus dem Eigenschaftenfenster oder über die Registerkarten UPDATE und DELETE in der Option Angeben einer benutzerdefinierten SQL-Anweisung oder gespeicherten Prozedur im Assistenten Datenquelle konfigurieren vorgenommen werden. Auch diese Änderung muss für jede Spalte in der und DeleteCommand
s-Klausel WHERE
vorgenommen werden, die UpdateCommand
Werte enthalten NULL
kann.
Wenn Sie dies auf unser Beispiel anwenden, ergeben sich die folgenden geänderten UpdateCommand
Werte und DeleteCommand
Werte:
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
Schritt 2: Hinzufügen einer GridView mit Den Optionen "Bearbeiten" und "Löschen"
Wenn SqlDataSource für die Unterstützung optimistischer Parallelität konfiguriert ist, bleibt nur noch das Hinzufügen eines Datenwebsteuerelements zu der Seite, die dieses Parallelitätssteuerelement verwendet. Fügen Sie für dieses Tutorial eine GridView hinzu, die sowohl Bearbeitungs- als auch Löschfunktionen bietet. Ziehen Sie dazu eine GridView aus der Toolbox auf die Designer, und legen Sie sie ID
auf festProducts
. Binden Sie es über das Smarttag von GridView an das ProductsDataSourceWithOptimisticConcurrency
in Schritt 1 hinzugefügte SqlDataSource-Steuerelement. Aktivieren Sie abschließend die Optionen Bearbeiten aktivieren und Löschen aktivieren über das Smarttag.
Abbildung 6: Binden der GridView an die SqlDataSource und Aktivieren der Bearbeitung und Löschung (Klicken, um das bild in voller Größe anzuzeigen)
Nachdem Sie gridView hinzugefügt haben, konfigurieren Sie dessen Darstellung, indem Sie boundField ProductID
entfernen, die ProductName
BoundField-Eigenschaft in HeaderText
Product ändern und das UnitPrice
BoundField so aktualisieren, dass seine HeaderText
Eigenschaft einfach Price ist. Im Idealfall wird die Bearbeitungsoberfläche erweitert, um einen RequiredFieldValidator für den ProductName
Wert und einen CompareValidator für den UnitPrice
Wert einzuschließen (um sicherzustellen, dass es sich um einen ordnungsgemäß formatierten numerischen Wert ist). Weitere Informationen zum Anpassen der Bearbeitungsschnittstelle von GridView finden Sie im Tutorial Anpassen der Datenänderungsschnittstelle .
Hinweis
Der Ansichtszustand von GridView muss aktiviert sein, da die ursprünglichen Werte, die von GridView an die SqlDataSource übergeben werden, im Ansichtszustand gespeichert werden.
Nachdem Sie diese Änderungen an GridView vorgenommen haben, sollte das deklarative Markup GridView und SqlDataSource in etwa wie folgt aussehen:
<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>
Um das Steuerelement für die optimistische Parallelität in Aktion zu sehen, öffnen Sie zwei Browserfenster, und laden Sie die OptimisticConcurrency.aspx
Seite in beiden. Klicken Sie in beiden Browsern auf die Schaltflächen Bearbeiten für das erste Produkt. Ändern Sie in einem Browser den Produktnamen, und klicken Sie auf Aktualisieren. Der Browser postback, und GridView kehrt in den Vorbearbeitungsmodus zurück, der den neuen Produktnamen für den gerade bearbeiteten Datensatz anzeigt.
Ändern Sie im zweiten Browserfenster den Preis (behalten Sie den Produktnamen jedoch als ursprünglichen Wert bei), und klicken Sie auf Aktualisieren. Beim Postback kehrt das Raster in den Vorbearbeitungsmodus zurück, aber die Änderung des Preises wird nicht aufgezeichnet. Der zweite Browser zeigt den gleichen Wert an wie der erste, der neue Produktname mit dem alten Preis. Die im zweiten Browserfenster vorgenommenen Änderungen gingen verloren. Darüber hinaus gingen die Änderungen ziemlich ruhig verloren, da es keine Ausnahme oder Meldung gab, die darauf hinweist, dass gerade ein Parallelitätsverstoß aufgetreten ist.
Abbildung 7: Die Änderungen im zweiten Browserfenster wurden im Hintergrund verloren (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Der Grund, warum die änderungen des zweiten Browsers nicht committet wurden, war, dass die UPDATE
Anweisung s-Klausel WHERE
alle Datensätze herausgefiltert und daher keine Zeilen beeinflusste. Sehen wir uns die UPDATE
-Anweisung noch einmal an:
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
Wenn das zweite Browserfenster den Datensatz aktualisiert, stimmt der in der WHERE
-Klausel angegebene ursprüngliche Produktname nicht mit dem vorhandenen Produktnamen überein (da er vom ersten Browser geändert wurde). Daher gibt die Anweisung [ProductName] = @original_ProductName
False zurück, und der UPDATE
wirkt sich nicht auf Datensätze aus.
Hinweis
Löschen funktioniert auf die gleiche Weise. Wenn zwei Browserfenster geöffnet sind, bearbeiten Sie zunächst ein bestimmtes Produkt mit einem, und speichern Sie dann die Änderungen. Nachdem Sie die Änderungen in dem einen Browser gespeichert haben, klicken Sie auf die Schaltfläche Löschen für dasselbe Produkt im anderen. Da die ursprünglichen Werte in der DELETE
Anweisung s-Klausel WHERE
nicht übereinstimmen, schlägt das Löschen automatisch fehl.
Aus der Perspektive des Endbenutzers im zweiten Browserfenster kehrt das Raster nach dem Klicken auf die Schaltfläche Aktualisieren in den Vorbearbeitungsmodus zurück, die Änderungen sind jedoch verloren gegangen. Es gibt jedoch kein visuelles Feedback, dass die Änderungen nicht beibehalten wurden. Wenn Änderungen eines Benutzers aufgrund einer Parallelitätsverletzung verloren gehen, wird er im Idealfall benachrichtigt und möglicherweise das Raster im Bearbeitungsmodus beibehalten. Sehen wir uns an, wie dies erreicht wird.
Schritt 3: Ermitteln, wann ein Parallelitätsverstoß aufgetreten ist
Da eine Parallelitätsverletzung die vorgenommenen Änderungen ablehnt, wäre es schön, den Benutzer zu benachrichtigen, wenn eine Parallelitätsverletzung aufgetreten ist. Fügen Sie zum Warnen des Benutzers oben auf der Seite ein Label Web-Steuerelement mit dem Namen ConcurrencyViolationMessage
hinzu, dessen Text
Eigenschaft die folgende Meldung anzeigt: Sie haben versucht, einen Datensatz zu aktualisieren oder zu löschen, der gleichzeitig von einem anderen Benutzer aktualisiert wurde. Überprüfen Sie die Änderungen des anderen Benutzers, und wiederholen Sie dann Das Update oder Löschen. Legen Sie die Eigenschaft des Label-Steuerelements CssClass
auf Warning fest. Hierbei handelt es sich um eine CSS-Klasse, die in Styles.css
definiert ist und Text in einer roten, kursiven, fetten und großen Schriftart anzeigt. Legen Sie schließlich die Eigenschaften Label s Visible
und EnableViewState
auf fest false
. Dadurch wird die Bezeichnung ausgeblendet, mit Ausnahme der Postbacks, bei denen die -Eigenschaft explizit auf true
festgelegt Visible
wird.
Abbildung 8: Hinzufügen eines Bezeichnungssteuerelements zur Seite zum Anzeigen der Warnung (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Beim Ausführen eines Updates oder Löschens werden die GridView-Ereignishandler RowUpdated
und RowDeleted
ausgelöst, nachdem die Datenquellensteuerung das angeforderte Update oder Löschvorgang ausgeführt hat. Wir können anhand dieser Ereignishandler bestimmen, wie viele Zeilen vom Vorgang betroffen waren. Wenn 0 Zeilen betroffen sind, möchten wir die ConcurrencyViolationMessage
Bezeichnung anzeigen.
Erstellen Sie einen Ereignishandler für das RowUpdated
- und RowDeleted
-Ereignis, und fügen Sie den folgenden Code hinzu:
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;
}
In beiden Ereignishandlern überprüfen wir die e.AffectedRows
-Eigenschaft und legen die Label-Eigenschaft Visible
true
auf festConcurrencyViolationMessage
, wenn sie gleich 0 ist. RowUpdated
Im Ereignishandler weisen wir gridView außerdem an, im Bearbeitungsmodus zu bleiben, indem wir die KeepInEditMode
Eigenschaft auf true festlegen. Dabei müssen wir die Daten erneut an das Raster binden, damit die Daten des anderen Benutzers in die Bearbeitungsoberfläche geladen werden. Dies wird durch Aufrufen der GridView s-Methode DataBind()
erreicht.
Wie Abbildung 9 zeigt, wird bei diesen beiden Ereignishandlern immer dann eine sehr auffällige Meldung angezeigt, wenn eine Parallelitätsverletzung auftritt.
Abbildung 9: Eine Meldung wird im Gesicht eines Nebenläufigkeitsverstoßes angezeigt (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Zusammenfassung
Beim Erstellen einer Webanwendung, bei der mehrere gleichzeitige Benutzer dieselben Daten bearbeiten können, ist es wichtig, Optionen für die Parallelitätssteuerung in Betracht zu ziehen. Standardmäßig verwenden die ASP.NET Datenwebsteuerelemente und Datenquellensteuerelemente keine Parallelitätssteuerung. Wie wir in diesem Tutorial gesehen haben, ist die Implementierung der Steuerung für optimistische Parallelität mit SqlDataSource relativ schnell und einfach. SqlDataSource übernimmt den größten Teil der Aufgaben beim Hinzufügen von erweiterten WHERE
Klauseln zu den automatisch generierten UPDATE
Und DELETE
-Anweisungen, es gibt jedoch einige Feinheiten bei der Behandlung von NULL
Wertspalten, wie im Abschnitt Richtig behandelte NULL
Werte erläutert.
Dieses Tutorial schließt unsere Untersuchung der SqlDataSource ab. In unseren verbleibenden Tutorials wird die Arbeit mit Daten mithilfe von ObjectDataSource und mehrstufiger Architektur wieder hergestellt.
Viel Spaß beim Programmieren!
Zum Autor
Scott Mitchell, Autor von sieben ASP/ASP.NET-Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft-Webtechnologien. Scott arbeitet als unabhängiger Berater, Trainer und Autor. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Er kann unter mitchell@4GuysFromRolla.comoder über seinen Blog erreicht werden, der unter http://ScottOnWriting.NETzu finden ist.
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für