Implémentation de l’accès concurrentiel optimiste avec SqlDataSource (VB)
par Scott Mitchell
Dans ce tutoriel, nous passons en revue les principes fondamentaux du contrôle d’accès concurrentiel optimiste, puis nous explorons comment l’implémenter à l’aide du contrôle SqlDataSource.
Introduction
Dans le tutoriel précédent, nous avons examiné comment ajouter des fonctionnalités d’insertion, de mise à jour et de suppression au contrôle SqlDataSource. En bref, pour fournir ces fonctionnalités, nous avions besoin de spécifier l’instruction SQL correspondante INSERT
UPDATE
, ou DELETE
dans les propriétés du contrôle , InsertCommand
UpdateCommand
ou DeleteCommand
, ainsi que les paramètres appropriés dans les InsertParameters
collections , UpdateParameters
et DeleteParameters
. Bien que ces propriétés et collections puissent être spécifiées manuellement, le bouton Avancé de l’Assistant Configuration de la source de données offre une case à cocher Générer INSERT
, UPDATE
et DELETE
des instructions qui créent automatiquement ces instructions en fonction de l’instruction SELECT
.
Avec la case à cocher Générer INSERT
, UPDATE
et DELETE
les instructions , la boîte de dialogue Options de génération SQL avancées inclut une option Utiliser l’accès concurrentiel optimiste (voir la Figure 1). Lorsqu’elles sont activées, les WHERE
clauses dans les instructions générées UPDATE
automatiquement et DELETE
sont modifiées pour effectuer la mise à jour ou la suppression uniquement si les données de base de données sous-jacentes n’ont pas été modifiées depuis le dernier chargement des données dans la grille par l’utilisateur.
Figure 1 : Vous pouvez ajouter la prise en charge de l’accès concurrentiel optimiste à partir de la boîte de dialogue Options de génération SQL avancées
Dans le didacticiel Implémentation de l’accès concurrentiel optimiste , nous avons examiné les principes fondamentaux du contrôle d’accès concurrentiel optimiste et comment l’ajouter à ObjectDataSource. Dans ce tutoriel, nous allons apporter des retouches sur les principes fondamentaux du contrôle d’accès concurrentiel optimiste, puis découvrir comment l’implémenter à l’aide de SqlDataSource.
Récapitulatif de l’accès concurrentiel optimiste
Pour les applications web qui permettent à plusieurs utilisateurs simultanés de modifier ou de supprimer les mêmes données, il existe une possibilité qu’un utilisateur remplace accidentellement les modifications d’un autre utilisateur. Dans le didacticiel Implémentation de l’accès concurrentiel optimiste , j’ai fourni l’exemple suivant :
Imaginez que deux utilisateurs, Jisun et Sam, visitaient une page dans une application qui permettait aux visiteurs de mettre à jour et de supprimer des produits via un contrôle GridView. Les deux cliquez sur le bouton Modifier pour Chai environ au même moment. Jisun remplace le nom du produit par Chai Tea et clique sur le bouton Mettre à jour. Le résultat net est une UPDATE
instruction qui est envoyée à la base de données, qui définit tous les champs de produit pouvant être mis à jour (même si Jisun n’a mis à jour qu’un seul champ, ProductName
). À ce stade, la base de données contient les valeurs Chai Tea, la catégorie Boissons, le fournisseur Liquides exotiques, et ainsi de suite pour ce produit particulier. Toutefois, l’écran GridView sur Sam affiche toujours le nom du produit dans la ligne GridView modifiable en tant que Chai. Quelques secondes après la validation des modifications de Jisun, Sam met à jour la catégorie en Condiments et clique sur Mettre à jour. Il en résulte une UPDATE
instruction envoyée à la base de données qui définit le nom du produit sur Chai, sur CategoryID
l’ID de catégorie Condiments correspondant, etc. Les modifications apportées par Jisun au nom du produit ont été remplacées.
La figure 2 illustre cette interaction.
Figure 2 : Lorsque deux utilisateurs mettent simultanément à jour un enregistrement, il est possible qu’un utilisateur modifie les autres (cliquez pour afficher l’image en taille réelle)
Pour empêcher ce scénario de se dérouler, une forme de contrôle d’accès concurrentiel doit être implémentée. Accès concurrentiel optimiste L’objectif de ce didacticiel est de supposer que même s’il peut y avoir des conflits d’accès concurrentiel de temps en temps, la grande majorité du temps de tels conflits ne se produisent pas. Par conséquent, en cas de conflit, le contrôle d’accès concurrentiel optimiste informe simplement l’utilisateur que ses modifications ne peuvent pas être enregistrées, car un autre utilisateur a modifié les mêmes données.
Notes
Pour les applications où il est supposé qu’il y aura de nombreux conflits d’accès concurrentiel ou si ces conflits ne sont pas tolérables, le contrôle d’accès concurrentiel pessimiste peut être utilisé à la place. Reportez-vous au didacticiel Implémentation de l’accès concurrentiel optimiste pour une discussion plus approfondie sur le contrôle d’accès concurrentiel pessimiste.
Le contrôle d’accès concurrentiel optimiste fonctionne en s’assurant que l’enregistrement en cours de mise à jour ou de suppression a les mêmes valeurs que lors du démarrage du processus de mise à jour ou de suppression. Par exemple, lorsque vous cliquez sur le bouton Modifier dans un GridView modifiable, les valeurs de l’enregistrement sont lues à partir de la base de données et affichées dans TextBoxes et d’autres contrôles Web. Ces valeurs d’origine sont enregistrées par GridView. Plus tard, une fois que l’utilisateur a apporté ses modifications et cliqué sur le bouton Mettre à jour, l’instruction UPDATE
utilisée doit prendre en compte les valeurs d’origine plus les nouvelles valeurs et mettre à jour l’enregistrement de base de données sous-jacent uniquement si les valeurs d’origine que l’utilisateur a commencé à modifier sont identiques aux valeurs toujours dans la base de données. La figure 3 illustre cette séquence d’événements.
Figure 3 : Pour que la mise à jour ou la suppression réussisse, les valeurs d’origine doivent être égales aux valeurs de base de données actuelles (cliquer pour afficher l’image en taille réelle)
Il existe différentes approches pour implémenter l’accès concurrentiel optimiste (voir La logique de mise à jour de l’accès concurrentiel optimiste de Peter A. Bromberg pour un bref aperçu d’un certain nombre d’options). La technique utilisée par sqlDataSource (ainsi que par les ADO.NET datasets typés utilisés dans notre couche d’accès aux données) augmente la WHERE
clause pour inclure une comparaison de toutes les valeurs d’origine. L’instruction suivante UPDATE
, par exemple, met à jour le nom et le prix d’un produit uniquement si les valeurs de base de données actuelles sont égales aux valeurs qui ont été récupérées à l’origine lors de la mise à jour de l’enregistrement dans GridView. Les @ProductName
paramètres et @UnitPrice
contiennent les nouvelles valeurs entrées par l’utilisateur, tandis que @original_ProductName
et @original_UnitPrice
contiennent les valeurs qui ont été initialement chargées dans gridView lorsque l’utilisateur a cliqué sur le bouton Modifier :
UPDATE Products SET
ProductName = @ProductName,
UnitPrice = @UnitPrice
WHERE
ProductID = @original_ProductID AND
ProductName = @original_ProductName AND
UnitPrice = @original_UnitPrice
Comme nous le verrons dans ce tutoriel, l’activation du contrôle d’accès concurrentiel optimiste avec SqlDataSource est aussi simple que de cocher une case à cocher.
Étape 1 : Création d’un SqlDataSource qui prend en charge l’accès concurrentiel optimiste
Commencez par ouvrir la OptimisticConcurrency.aspx
page à partir du SqlDataSource
dossier. Faites glisser un contrôle SqlDataSource de la boîte à outils sur le Designer, en lui donnant ID
la ProductsDataSourceWithOptimisticConcurrency
valeur . Cliquez ensuite sur le lien Configurer la source de données à partir de la balise active du contrôle. À partir du premier écran de l’Assistant, choisissez d’utiliser le NORTHWINDConnectionString
et cliquez sur Suivant.
Figure 4 : Choisir d’utiliser le (Cliquer pour afficher l’imageNORTHWINDConnectionString
en taille réelle)
Pour cet exemple, nous allons ajouter un GridView qui permet aux utilisateurs de modifier la Products
table. Par conséquent, dans l’écran Configurer l’instruction Select, choisissez le Products
tableau dans la liste déroulante et sélectionnez les ProductID
colonnes , ProductName
, UnitPrice
et Discontinued
, comme illustré dans la figure 5.
Figure 5 : À partir de la Products
table, renvoyer les ProductID
colonnes , ProductName
, UnitPrice
et Discontinued
(cliquez pour afficher l’image en taille réelle)
Après avoir sélectionné les colonnes, cliquez sur le bouton Avancé pour afficher la boîte de dialogue Options avancées de génération SQL. Cochez les cases Générer INSERT
les instructions , UPDATE
et DELETE
et et Utiliser l’accès concurrentiel optimiste, puis cliquez sur OK (reportez-vous à la figure 1 pour obtenir une capture d’écran). Terminez l’Assistant en cliquant sur Suivant, puis sur Terminer.
Après avoir terminé l’Assistant Configuration de la source de données, prenez un moment pour examiner les propriétés et UpdateCommand
résultantesDeleteCommand
, ainsi que les DeleteParameters
collections et .UpdateParameters
Le moyen le plus simple consiste à cliquer sur l’onglet Source dans le coin inférieur gauche pour afficher la syntaxe déclarative de la page. Vous y trouverez la UpdateCommand
valeur suivante :
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
Avec sept paramètres dans la UpdateParameters
collection :
<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>
De même, la propriété et DeleteParameters
la DeleteCommand
collection doivent ressembler à ce qui suit :
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>
En plus d’augmenter les WHERE
clauses des UpdateCommand
propriétés et ( DeleteCommand
et d’ajouter les paramètres supplémentaires aux collections de paramètres respectives), la sélection de l’option Utiliser l’accès concurrentiel optimiste ajuste deux autres propriétés :
- Remplace la
ConflictDetection
propriété deOverwriteChanges
(valeur par défaut) parCompareAllValues
- Remplace la
OldValuesParameterFormatString
propriété ( {0} valeur par défaut) par original_{0} .
Lorsque le contrôle Web de données appelle la méthode Ou Delete()
sqlDataSourceUpdate()
, il transmet les valeurs d’origine. Si la propriété SqlDataSource est ConflictDetection
définie sur CompareAllValues
, ces valeurs d’origine sont ajoutées à la commande . La OldValuesParameterFormatString
propriété fournit le modèle de nommage utilisé pour ces paramètres de valeur d’origine. L’Assistant Configuration de la source de données utilise original_{0} et nomme chaque paramètre d’origine dans les DeleteCommand
UpdateCommand
collections et propriétés et UpdateParameters
et en DeleteParameters
conséquence.
Notes
Étant donné que nous n’utilisons pas les fonctionnalités d’insertion du contrôle SqlDataSource, n’hésitez pas à supprimer la InsertCommand
propriété et sa InsertParameters
collection.
Gestion correcte desNULL
valeurs
Malheureusement, les instructions augmentées UPDATE
et DELETE
générées automatiquement par l’Assistant Configurer la source de données lors de l’utilisation de l’accès concurrentiel optimiste ne fonctionnent pas avec les enregistrements qui contiennent des NULL
valeurs. Pour voir pourquoi, considérez nos 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
La UnitPrice
colonne de la Products
table peut avoir des NULL
valeurs. Si un enregistrement particulier a une NULL
valeur pour UnitPrice
, la partie clause [UnitPrice] = @original_UnitPrice
prend toujours la WHERE
valeur False, car NULL = NULL
retourne toujours False. Par conséquent, les enregistrements qui contiennent des NULL
valeurs ne peuvent pas être modifiés ou supprimés, car les UPDATE
clauses d’instructions WHERE
et DELETE
ne retournent aucune ligne à mettre à jour ou à supprimer.
Notes
Ce bogue a été signalé pour la première fois à Microsoft en juin 2004 dans SqlDataSource Génère des instructions SQL incorrectes et devrait être corrigé dans la prochaine version de ASP.NET.
Pour résoudre ce problème, nous devons mettre à jour manuellement les WHERE
clauses dans les UpdateCommand
propriétés et DeleteCommand
pour toutes les colonnes qui peuvent avoir des NULL
valeurs. En général, remplacez par [ColumnName] = @original_ColumnName
:
(
([ColumnName] IS NULL AND @original_ColumnName IS NULL)
OR
([ColumnName] = @original_ColumnName)
)
Cette modification peut être effectuée directement via le balisage déclaratif, via les options UpdateQuery ou DeleteQuery de l’Fenêtre Propriétés, ou via les onglets UPDATE et DELETE de l’option Spécifier une instruction SQL personnalisée ou une procédure stockée dans l’Assistant Configurer la source de données. Là encore, cette modification doit être effectuée pour chaque colonne de la UpdateCommand
clause et DeleteCommand
s WHERE
qui peut contenir des NULL
valeurs.
L’application de ceci à notre exemple entraîne les modifications et DeleteCommand
valeurs suivantes 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
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
Étape 2 : Ajout d’un GridView avec les options Modifier et Supprimer
Avec SqlDataSource configuré pour prendre en charge l’accès concurrentiel optimiste, il ne reste plus qu’à ajouter un contrôle Web de données à la page qui utilise ce contrôle d’accès concurrentiel. Pour ce tutoriel, nous allons ajouter un GridView qui fournit à la fois des fonctionnalités d’édition et de suppression. Pour ce faire, faites glisser un GridView de la boîte à outils vers le Designer et définissez son ID
sur Products
. À partir de la balise active gridView, liez-la au ProductsDataSourceWithOptimisticConcurrency
contrôle SqlDataSource ajouté à l’étape 1. Enfin, case activée les options Activer la modification et Activer la suppression de la balise active.
Figure 6 : Lier gridView à SqlDataSource et Activer la modification et la suppression (cliquer pour afficher l’image en taille réelle)
Après avoir ajouté GridView, configurez son apparence en supprimant BoundField ProductID
, en remplaçant la ProductName
propriété s de HeaderText
BoundField sur Product et en mettant à jour le UnitPrice
BoundField afin que sa HeaderText
propriété soit simplement Price. Dans l’idéal, nous améliorerons l’interface de modification pour inclure un RequiredFieldValidator pour la ProductName
valeur et un CompareValidator pour la UnitPrice
valeur (pour nous assurer qu’il s’agit d’une valeur numérique correctement mise en forme). Pour plus d’informations sur la personnalisation de l’interface de modification de données , reportez-vous au tutoriel Personnalisation de l’interface de modification de GridView.
Notes
L’état d’affichage de GridView doit être activé, car les valeurs d’origine passées de GridView à SqlDataSource sont stockées dans l’état d’affichage.
Après avoir apporté ces modifications à GridView, le balisage déclaratif GridView et SqlDataSource doit ressembler à ce qui suit :
<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>
Pour voir le contrôle d’accès concurrentiel optimiste en action, ouvrez deux fenêtres de navigateur et chargez la OptimisticConcurrency.aspx
page dans les deux. Cliquez sur les boutons Modifier pour le premier produit dans les deux navigateurs. Dans un navigateur, modifiez le nom du produit et cliquez sur Mettre à jour. Le navigateur est publié et gridView revient à son mode de pré-édition, affichant le nouveau nom de produit pour l’enregistrement qui vient d’être modifié.
Dans la deuxième fenêtre de navigateur, modifiez le prix (en conservant le nom du produit comme valeur d’origine), puis cliquez sur Mettre à jour. Lors de la publication, la grille revient à son mode de pré-édition, mais la modification du prix n’est pas enregistrée. Le deuxième navigateur affiche la même valeur que le premier le nouveau nom de produit avec l’ancien prix. Les modifications apportées dans la deuxième fenêtre de navigateur ont été perdues. En outre, les modifications ont été perdues assez discrètement, car il n’y avait aucune exception ou message indiquant qu’une violation de la concurrence vient de se produire.
Figure 7 : Les modifications apportées à la deuxième fenêtre du navigateur ont été perdues en mode silencieux (cliquer pour afficher l’image en taille réelle)
La raison pour laquelle les modifications apportées au deuxième navigateur n’ont pas été validées est que la clause s de l’instruction UPDATE
WHERE
a filtré tous les enregistrements et n’a donc pas affecté les lignes. Examinons à nouveau l’instruction 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
Lorsque la deuxième fenêtre de navigateur met à jour l’enregistrement, le nom de produit d’origine spécifié dans la WHERE
clause ne correspond pas au nom de produit existant (puisqu’il a été modifié par le premier navigateur). Par conséquent, l’instruction [ProductName] = @original_ProductName
retourne False et n’affecte UPDATE
aucun enregistrement.
Notes
La suppression fonctionne de la même manière. Avec deux fenêtres de navigateur ouvertes, commencez par modifier un produit donné avec une, puis enregistrez ses modifications. Après avoir enregistré les modifications dans l’un des navigateurs, cliquez sur le bouton Supprimer pour le même produit dans l’autre. Étant donné que les valeurs d’origine ne correspondent pas à la clause s de l’instruction DELETE
WHERE
, la suppression échoue en mode silencieux.
Du point de vue de l’utilisateur final dans la deuxième fenêtre du navigateur, après avoir cliqué sur le bouton Mettre à jour, la grille revient au mode de pré-édition, mais ses modifications ont été perdues. Cependant, il n’y a aucun commentaire visuel que leurs modifications n’ont pas collé. Dans l’idéal, si les modifications d’un utilisateur sont perdues en cas de violation d’accès concurrentiel, nous l’informons et, peut-être, gardons la grille en mode édition. Voyons comment y parvenir.
Étape 3 : Déterminer quand une violation d’accès concurrentiel s’est produite
Étant donné qu’une violation d’accès concurrentiel rejette les modifications apportées, il serait agréable d’avertir l’utilisateur lorsqu’une violation d’accès concurrentiel s’est produite. Pour alerter l’utilisateur, ajoutons un contrôle Label Web en haut de la page nommée ConcurrencyViolationMessage
dont Text
la propriété affiche le message suivant : Vous avez tenté de mettre à jour ou de supprimer un enregistrement qui a été mis à jour simultanément par un autre utilisateur. Passez en revue les modifications apportées par l’autre utilisateur, puis rétablissez votre mise à jour ou suppression. Définissez la propriété s du CssClass
contrôle Label sur Warning, qui est une classe CSS définie dans Styles.css
qui affiche le texte dans une police rouge, italique, en gras et grande. Enfin, définissez les propriétés Label s Visible
et EnableViewState
sur False
. Cela masque l’étiquette, à l’exception uniquement des publications pour lesquelles nous définissons explicitement sa Visible
propriété sur True
.
Figure 8 : Ajouter un contrôle d’étiquette à la page pour afficher l’avertissement (cliquer pour afficher l’image en taille réelle)
Lors d’une mise à jour ou d’une suppression, les gestionnaires d’événements GridView se RowUpdated
RowDeleted
déclenchent après que son contrôle de source de données a effectué la mise à jour ou la suppression demandée. Nous pouvons déterminer le nombre de lignes affectées par l’opération à partir de ces gestionnaires d’événements. Si aucune ligne n’a été affectée, nous voulons afficher l’étiquette ConcurrencyViolationMessage
.
Créez un gestionnaire d’événements pour les RowUpdated
événements et et RowDeleted
ajoutez le code suivant :
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
Dans les deux gestionnaires d’événements, nous case activée la e.AffectedRows
propriété et, si elle est égale à 0, définissez la ConcurrencyViolationMessage
propriété Label s Visible
sur True
. Dans le RowUpdated
gestionnaire d’événements, nous demandons également à GridView de rester en mode édition en définissant la KeepInEditMode
propriété sur true. Ce faisant, nous devons lier les données à la grille afin que les données de l’autre utilisateur soient chargées dans l’interface d’édition. Pour ce faire, appelez la méthode s DataBind()
GridView.
Comme le montre la figure 9, avec ces deux gestionnaires d’événements, un message très visible s’affiche chaque fois qu’une violation d’accès concurrentiel se produit.
Figure 9 : Un message s’affiche dans la face d’une violation d’accès concurrentiel (cliquer pour afficher l’image en taille réelle)
Résumé
Lors de la création d’une application web dans laquelle plusieurs utilisateurs simultanés peuvent modifier les mêmes données, il est important de prendre en compte les options de contrôle de concurrence. Par défaut, les contrôles web ASP.NET données et les contrôles de source de données n’utilisent aucun contrôle d’accès concurrentiel. Comme nous l’avons vu dans ce tutoriel, l’implémentation d’un contrôle d’accès concurrentiel optimiste avec SqlDataSource est relativement rapide et facile. SqlDataSource gère la majeure partie du travail pour l’ajout de clauses augmentées WHERE
aux instructions générées UPDATE
automatiquement et DELETE
, mais il existe quelques subtilités dans la gestion des NULL
colonnes de valeur, comme indiqué dans la section Gestion correcte des NULL
valeurs.
Ce tutoriel conclut notre examen de SqlDataSource. Nos tutoriels restants retourneront à l’utilisation des données à l’aide de l’objectDataSource et de l’architecture hiérarchisée.
Bonne programmation !
À propos de l’auteur
Scott Mitchell, auteur de sept livres ASP/ASP.NET et fondateur de 4GuysFromRolla.com, travaille avec les technologies Web Microsoft depuis 1998. Scott travaille comme consultant indépendant, formateur et écrivain. Son dernier livre est Sams Teach Yourself ASP.NET 2.0 in 24 Heures. Il est accessible à l’adressemitchell@4GuysFromRolla.com . ou via son blog, qui peut être trouvé à l’adresse http://ScottOnWriting.NET.