Implémentation de l’accès concurrentiel optimiste avec SqlDataSource (C#)
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
, ou DELETE
dans les propriétés de contrôle s InsertCommand
, UpdateCommand
ou , ainsi DeleteCommand
que les paramètres appropriés dans les InsertParameters
collections , UpdateParameters
et DeleteParameters
. UPDATE
Bien que ces propriétés et collections puissent être spécifiées manuellement, le bouton Avancé de l’Assistant Configurer 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
.
En plus de la case à cocher Générer INSERT
, UPDATE
et DELETE
des instructions, la boîte de dialogue Options de génération SQL avancées inclut une option Utiliser l’accès concurrentiel optimiste (voir figure 1). Lorsqu’elles sont cochéesUPDATE
, les WHERE
clauses dans les instructions générées 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 par l’utilisateur dans la grille.
Figure 1 : Vous pouvez ajouter la prise en charge de la concurrence optimiste à partir de la boîte de dialogue Options de génération SQL avancées
De retour dans le tutoriel Implémentation de la concurrence 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 retoucher les éléments essentiels du contrôle d’accès concurrentiel optimiste, puis explorer 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 est possible qu’un utilisateur remplace accidentellement un autre utilisateur. Dans le didacticiel Implémentation de la concurrence optimiste , j’ai fourni l’exemple suivant :
Imaginez que deux utilisateurs, Jisun et Sam, consultaient une page d’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 à peu près en même temps. Jisun remplace le nom du produit par Chai Tea et clique sur le bouton Mettre à jour. Le résultat net est une UPDATE
instruction 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 a 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 vers 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, le CategoryID
sur l’ID de catégorie Condiments correspondant, et ainsi de suite. 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 à jour simultanément un enregistrement, il est possible qu’un utilisateur change de remplacer 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’accent de ce didacticiel fonctionne sur l’hypothèse 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 de tels conflits ne sont pas tolérables, le contrôle d’accès concurrentiel pessimiste peut être utilisé à la place. Pour une discussion plus approfondie sur le contrôle d’accès concurrentiel pessimiste, reportez-vous au didacticiel Implémentation de l’accès concurrentiel optimiste.
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 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 la concurrence optimiste de Peter A. Bromberg pour un bref aperçu de plusieurs 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 le GridView lorsque vous avez 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.
É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 à partir de la boîte à outils sur le Designer, et paramètres sa ID
propriété sur ProductsDataSourceWithOptimisticConcurrency
. Ensuite, cliquez sur le lien Configurer la source de données à partir de la balise active du contrôle. Dans le premier écran de l’Assistant, choisissez d’utiliser le NORTHWINDConnectionString
et cliquez sur Suivant.
Figure 4 : Choisir d’utiliser le NORTHWINDConnectionString
(Cliquer pour afficher l’image 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 Sélectionner, choisissez le Products
tableau dans la liste déroulante et sélectionnez les colonnes , ProductName
, UnitPrice
et Discontinued
, comme illustré dans la ProductID
figure 5.
Figure 5 : À partir de la Products
table, renvoyer les ProductID
colonnes , ProductName
, UnitPrice
et Discontinued
(cliquer pour afficher l’image en taille réelle)
Après avoir choisi les colonnes, cliquez sur le bouton Avancé pour afficher la boîte de dialogue Options de génération SQL avancée. Cochez les cases Générer INSERT
les instructions , UPDATE
et DELETE
et Utiliser la concurrence 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 Configurer la source de données, prenez un moment pour examiner les propriétés et les collections et UpdateCommand
DeleteParameters
et UpdateParameters
résultantesDeleteCommand
. La méthode la 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 une UpdateCommand
valeur de :
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 la concurrence optimiste ajuste deux autres propriétés :
- Modifie la
ConflictDetection
propriété deOverwriteChanges
(la valeur par défaut) enCompareAllValues
- 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 SqlDataSource Update()
ou Delete()
, il transmet les valeurs d’origine. Si la propriété sqlDataSource ConflictDetection
a la CompareAllValues
valeur , 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 Configurer la source de données utilise original_{0} et nomme chaque paramètre d’origine dans les UpdateCommand
collections et DeleteCommand
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 la concurrence optimiste ne fonctionnent pas avec les enregistrements qui contiennent des NULL
valeurs. Pour en savoir plus, considérez nos données 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
La UnitPrice
colonne de la Products
table peut avoir des NULL
valeurs. Si un enregistrement particulier a une NULL
valeur pour UnitPrice
, la partie de [UnitPrice] = @original_UnitPrice
clause WHERE
est toujours évaluée sur 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 résolu 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 à partir du 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 de 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 UpdateCommand
et DeleteCommand
les valeurs suivantes :
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 d’édition et de suppression
Avec SqlDataSource configuré pour prendre en charge la concurrence 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, ajoutons 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 sur le Designer et définissez son ID
sur Products
. À partir de la balise active GridView, liez-la ProductsDataSourceWithOptimisticConcurrency
au 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 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;
}
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.