Les Labs Microsoft
Section C# / Asp.Net du site http://phenix.developez.com
par Patrick VALERI
Plan du site - Autres sections
Labs ASP.NET v1.1 Aurélien Norie & Sébastien Bovo [Microsoft]
J'ai repris les codes d'origine VB.NET en C# et apporter quelques commentaires.
Lab04
But du Lab
Le but de ce Lab est de facilement manipuler les données à travers les contrôles Web serveur fournis à l’aide d’ADO.NET.
Exercice 1 – Mise à jour de données à l’aide d’une DataList
- Lancer Visual Studio .NET
- Activer le menu « Fichier/Nouveau/Projet… »
- Choisir « Projets Visual Basic » et « Application Web ASP.NET »
- Pour l’emplacement, utiliser « http://localhost/04VBAccesAuxDonnees »
- Placer un contrôle DataList sur la page « WebForm1.aspx »
- En haut de la page de code behind, ajouter l’espace de nom SqlClient de la manière suivante :
Imports System.Data.SqlClient
Bien entendu en C# :
Using System.Data.SqlClient;
- Ajouter dans le code de la page une méthode appelée « FillDataList() » qui va lier la DataList à une base de données. Dans cet exemple, nous utiliserons la table « authors » de la base de données « pubs » du serveur SQL local.
Ici, les auteurs n’empruntent pas une méthode automatique propre à Visual Studio 2003 (Quelle version avaient t’ils ?). En voici une :Dans SQL 2000, la base de données Pubs existe dés l’installation, il suffit donc de créer une SqlConnection , créer un SqlDataAdapter et le configurer puis créer un Dataset et configurer de quoi le remplir. Rappelons qu’un DataSet est prévu pour fonctionner en mode déconnecté.
Allons-y :
Outils
Se connecter à la base de données
Onglet Fournisseurs
Microsoft OLE DB Provider for SQL server
Onglet connexion choisir la sécurité intégré ou non (pour les postes non-Windows) et renseigner le serveur SQL et la BDD Pubs.
Après il suffit de glisser la table Authors ( et seulement celle-là) ce qui créait SqlConnection1 et SqlDataAdapter1. Un clic droit sur SqlDataAdapter1 « Configurer l’adaptateur de données » et en SQL2000 il n’y a aucun souci pour générer le groupe de requêtes SQL Select, Insert, Update et Delete .Pour MySQL c’est moins évident, l’utilisation de quote ‘ ’ et la non utilisation de parenthèses est souvent requise dans la requête Update par exemple. Puis il reste à générer le groupe de données pour créer le dataSet11 qui est mappé dans le DataSet1.xsd avec un jeu de données adapté. Je peux en rajouter plus tard dans ce même DataSet1.
Dans le Code-Behind, on pourra dilater la zone « Code généré par le Concepteur Web Form » pour voir le code SQL généré. Il ne reste plus qu’à renseigner la propriété DataSource de DataList1 avec « dataSet11 ». La suite c’est de remplir le dataSet11 à l’ouverture de la page ou avec un bouton de commande. Si je vais insister un peu sur ce chapitre, c’est dans le cadre d’une « industrialisation » du développement. Il est quand même plus pratique d’utiliser les possibilités de mappage XML plutôt que de retaper du code à chaque fois.
Private Sub fillDataList()
Dim cn As New SqlConnection("server=(local);database=pubs;user id=sa;password=saPassword")
Dim sql As String = "Select * from authors"
Dim cmd As New SqlDataAdapter(sql, cn)
Dim ds As New DataSet
cmd.Fill(ds, "Authors")
DataList1.DataSource = ds.Tables("authors").DefaultView
DataList1.DataBind()
End Sub
- Dans l'événement « Page_Load », placer le code permettant d'appeler la méthode FillDataList la première fois que l'on navigue sur la page.
Private Sub Page_Load( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If Not Page.IsPostBack Then
fillDataList()
End If
End Sub |
- Paramétrer la DataList afin d’afficher les données. Pour cela, dans le code HTML de la page, ajouter un « ItemTemplate » entre les balises ouvrantes et fermantes du contrôle DataList comme montré ci-dessous.
< ItemTemplate >
< table bgcolor ="#f0f0f0" width ="100%">
< tr bgcolor ="#000000">
< td colspan ="2">
< asp:Label Font-Bold ="True" ForeColor ="#ffffff" text =' <%#Databinder.Eval(Container.DataItem, "au_id") %> ' Runat ="server" ID ="Label1"/>
</ td >
</ tr >
< tr >
< td >Prénom : </ td >
< td >
<%#Databinder.Eval(Container.DataItem, "au_fname") %>
</ td >
</ tr >
< tr >
< td >Nom : </ td >
< td >
<%#Databinder.Eval(Container.DataItem, "au_lname") %>
</ td >
</ tr >
< tr >
< td colspan ="2">
< asp:Button CommandName ="Edit" Text ="Edition" Runat ="server" ID ="Button1"/>
</ td >
</ tr >
</ table >
</ ItemTemplate > |
- Un ItemTemplate est un modèle qui est utilisé pour l'affichage de chaque élément de la liste retournée par la requête SQL. Ce modèle va afficher les données de la manière suivante :
- Chaque élément de la liste est affiché sou s forme de tableau.
- L'identifiant de l'auteur est affiché dans un Label.
- Le nom de l'auteur est rendu en tant que texte.
- Un bouton est ajouté à ce modèle afin de passer en mode "Edition".
- Pour en terminer avec l'affichage des données, attribuer à la propriété « RepeatColumns » du contrôle DataList la valeur 4. Cela a pour effet d'afficher les données sur 4 colonnes.
- Compiler et afficher la page dans le navigateur.
- Afin de pouvoir éditer les données, ajouter au contrôle Datalist un « EditItemTemplate ». Comme son nom l'indique, l'EditItemTemplate est un modèle spécifiant l'affichage à mettre en œuvre pour effectuer l'édition des données. Construire ce modèle de la même manière que l'ItemTemplate créé dans la partie précédente (à savoir sous forme de tableau). Apporter les modifications suivantes :
- Le nom et le prénom seront affichés dans une zone de saisie afin de pouvoir les modifier.
- Deux boutons "Annuler" et "Mettre à jour" sont ajoutés. Ils ont pour but d'annuler l'édition ou d'appeler une méthode de mise à jour des données saisies dans la base de données.
< EditItemTemplate >
< table bgcolor ="#f0f0f0" width ="100%">
< tr bgcolor ="#000000">
< td colspan ="2">
< asp:Label id ="lblId" Font-Bold ="True" ForeColor ="#ffffff" text =' <%#Databinder.Eval(Container.DataItem, "au_id") %> ' Runat ="server" />
</ td >
</ tr >
< tr >
< td >Prénom : </ td >
< td >
< input type ="text" id ="txtFirst" value =' <%#Databinder.Eval(Container.DataItem, "au_fname") %> ' runat ="server" NAME ="txtFirst"/>
</ td >
</ tr >
< tr >
< td >Nom : </ td >
< td >
< input type ="text" id ="txtLast" value =' <%#Databinder.Eval(Container.DataItem, "au_lname") %> ' runat ="server" NAME ="txtLast"/>
</ td >
</ tr >
< tr >
< td colspan ="2">
< asp:Button CommandName ="Update" Text ="Mettre à jour" Runat ="server" ID ="Button2"/>
< asp:Button CommandName ="Cancel" Text ="Annuler" Runat ="server" ID ="Button3"/>
</ td >
</ tr >
</ table >
</ EditItemTemplate > |
- Afin d'afficher en mode édition l'élément choisi, ajouter un gestionnaire d'événement « EditCommand » pour le contrôle DataList dans le code behind.
- Spécifier l'élément qui doit être affiché en mode édition à l’aide de la propriété « EditItemIndex » de la DataList
- Appeller de nouveau la méthode FillDataList() afin de mettre à jour l'affichage de la table. Le code est le suivant.
Private Sub DataList1_EditCommand( ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) Handles DataList1.EditCommand
DataList1.EditItemIndex = e.Item.ItemIndex
fillDataList()
End Sub
|
- Compiler et naviguer vers la page.
- Cliquer sur un bouton « Edition » afin de voir le changement
- Dans le code behind, créer une méthode appelée « SaveRecordToDatabase » qui va mettre à jour la base de données :
Private Sub SaveRecordToDatabase( ByVal _id As String, ByVal _first As String, ByVal _last As String)
Dim sql As String
Dim cnn As SqlConnection = New SqlConnection("server=(local);database=pubs;user id=sa;password= saPassword")
sql = "update authors set au_fname='" & _first & "', "
sql = sql & "au_lname='" & _last & "' where au_id='" & _id & "'"
Dim cmd As New SqlCommand(sql, cnn)
cnn.Open()
cmd.ExecuteNonQuery()
cnn.Close()
End Sub |
La technique ci-dessus me paraît peu judicieuse. En effet une nouvelle connexion implique une consommation supplémentaire de ressource sur la base de données. Il suffit d’utiliser la même connexion, de créer des maps supplémentaires souvent avec la même requête SQL. Comme ici il s’agit d’un update il n’est pas besoin de créer une connexion supplémentaire ni de map Dataset supplémentaire par rapport à la fonction Datafill().
Le problème du code ci-dessus est que nous n’avons pas de portée sur la connexion cn « private » de cette fonction .Aussi il est préférable d’utiliser la SqlConnection dont la portée est celle de la classe WebForm1 : elle porte le nom de sqlConnection1. D’autre part la situation est la même pour la mise à jour de la table puisqu’il est préférable de remettre à jour le DataSet puis d’utiliser la commande update générique de Visual Studio qui s’appelle dans notre cas sqlUpdateCommand1. En voici le libellé :
this .sqlUpdateCommand1.CommandText = @"UPDATE dbo.authors SET au_id = @au_id, au_lname = @au_lname, au_fname = @au_fname, phone = @phone, address = @address, city = @city, state = @state, zip = @zip, contract = @contract WHERE (au_id = @Original_au_id) AND (address = @Original_address OR @Original_address IS NULL AND address IS NULL) AND (au_fname = @Original_au_fname) AND (au_lname = @Original_au_lname) AND (city = @Original_city OR @Original_city IS NULL AND city IS NULL) AND (contract = @Original_contract) AND (phone = @Original_phone) AND (state = @Original_state OR @Original_state IS NULL AND state IS NULL) AND (zip = @Original_zip OR @Original_zip IS NULL AND zip IS NULL); SELECT au_id, au_lname, au_fname, phone, address, city, state, zip, contract FROM dbo.authors WHERE (au_id = @au_id)";
On voit qu’elle fait appel aux variables comme @au_id dont on s’affranchit puisque le dataSet une fois mise à jour la requête a tout les renseignements suffisants pour mettre la base de données à jour.
En clair l’ensemble de ce code ne sert à rien puisque l’idée principale est de séparer le code du frontal c’est à dire d’avoir une lisibilité du code suffisante pour avoir une idée précise de l’utilité du frontal HTML .Voici le code des auteurs
- Appeler cette méthode dans le gestionnaire d'événements « UpdateCommand » du contrôle DataList.
- Une fois la méthode « SaveRecordToDatabase » appelée, sortir du mode édition en précisant -1 comme valeur de « EditItemIndex » du contrôle DataList.
- Appeler la méthode « fillDataList ».
Private Sub DataList1_UpdateCommand( ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) Handles DataList1.UpdateCommand
Dim first As HtmlInputText = CType(e.Item.FindControl("txtFirst"), HtmlInputText)
Dim last As HtmlInputText = CType(e.Item.FindControl("txtLast"), HtmlInputText)
Dim id As Label = CType(e.Item.FindControl("LblId"), Label)
SaveRecordToDatabase(id.Text, first.Value, last.Value)
DataList1.EditItemIndex = -1
fillDataList()
End Sub |
- Tester la mise à jour des données : Modifier le nom ou le prénom d'un auteur et cliquez sur le bouton « Mettre à jour ». Observer que la modification a été prise en compte et que la liste affiche maintenant les auteurs avec la valeur saisie.
- Il ne reste plus qu'à gérer le clic sur le bouton « Annuler ». Pour cela, écrire le gestionnaire d'événement « CancelCommand » du contrôle DataList.
- Dans ce gestionnaire, sortir du mode édition en précisant -1 comme valeur de EditItemIndex du contrôle DataList, puis réafficher la liste.
Private Sub DataList1_CancelCommand( ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) Handles DataList1.CancelCommand
DataList1.EditItemIndex = -1
fillDataList()
End Sub |
Et maintenant voici ce que j’ai fait :
private void Page_Load( object sender, System.EventArgs e)
{
if (!IsPostBack)
{
sqlDataAdapter1.Fill(dataSet11);//Pour remplir le // DataSet avec la requête sqlSelectCommand1
DataList1.DataBind();
}
}
private void DataList1_EditCommand( object source, System.Web.UI.WebControls.DataListCommandEventArgs e)
{
sqlDataAdapter1.Fill(dataSet11);
//ci-dessous la propriété « EditItemIndex » de Datalist1 est de
// la valeur de l'item sélectionné pr l’utilisateur
DataList1.EditItemIndex = e.Item.ItemIndex;
DataList1.DataBind(); // On rafraîchit pour visualiser l’action en cours
}
private void DataList1_UpdateCommand( object source, System.Web.UI.WebControls.DataListCommandEventArgs e)
{
sqlDataAdapter1.Fill(dataSet11); // Pour remplir à nouveau // le DataSet puisque la connexion // est déjà refermée
// Ci-dessous on va remettre à jour le DataSet avant d’exécuter la //requête sqlUpdateCommand mais
//ici la méthode direct pour récupérer « Le_prénom » et « Le_nom »
// passe par un cast depuis les objet HtmlInputText txtFirst et //txtLast de la page en cours car ses valeurs n’existent pas dans le //Code-Behind
HtmlInputText LblFirst= (HtmlInputText)(e.Item.FindControl("txtFirst"));
HtmlInputText LblLast = (HtmlInputText)(e.Item.FindControl("txtLast"));
dataSet11.authors.Rows[e.Item.ItemIndex][2]= LblFirst.Value;
dataSet11.authors.Rows[e.Item.ItemIndex][1]= LblLast.Value;
sqlDataAdapter1.Update(dataSet11);
//ci-dessous on vérifie qu’en rechargeant depuis la base de données, les valeurs on bien été validées
sqlDataAdapter1.Fill(dataSet11) la base
DataList1.EditItemIndex = -1;
DataList1.DataBind();
}
private void DataList1_CancelCommand( object source, System.Web.UI.WebControls.DataListCommandEventArgs e)
{
sqlDataAdapter1.Fill(dataSet11);
DataList1.EditItemIndex = -1;
DataList1.DataBind();
} |
Ici les temps d’exécution au niveau du serveur SQL sont excellents !
Exercice 2 – Contrôle DataGrid et Appel d’une procédure stockée
- Ajouter une nouvelle page « DataGridProcedure.aspx »
- Ajouter sur cette page, sans renommer les contrôles :
- deux contrôles « Label »
- deux « Calendar »
- un contrôle « Button »
- ajouter aussi un autre « Label » pour le titre
- Ajouter un contrôle « DataGrid » en dessous du bouton :
- Double-cliquer sur le bouton pour afficher le code behind
- Ajouter en tout début de la page « DataGridProcedure.aspx.vb » :
Imports System.Data
Imports System.Data.SqlClient
- Pour l’évènement « click » du bouton, utiliser le code suivant :
Private Sub Button1_Click( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim DS As DataSet
Dim MyConnection As SqlConnection
Dim MyCommand As SqlDataAdapter
MyConnection = New SqlConnection("server=(local);database=northwind;user id=sa;password= saPassword")
MyCommand = New SqlDataAdapter("Employee Sales By Country", MyConnection)
MyCommand.SelectCommand.CommandType = CommandType.StoredProcedure
MyCommand.SelectCommand.Parameters.Add( New SqlParameter("@Beginning_Date", SqlDbType.DateTime))
MyCommand.SelectCommand.Parameters("@Beginning_Date").Value = Calendar1.SelectedDate
MyCommand.SelectCommand.Parameters.Add( New SqlParameter("@Ending_Date", SqlDbType.DateTime))
MyCommand.SelectCommand.Parameters("@Ending_Date").Value = Calendar2.SelectedDate
DS = New DataSet
MyCommand.Fill(DS, "Sales")
DataGrid1.DataSource = DS.Tables("Sales").DefaultView
DataGrid1.DataBind()
End Sub |
Et en C# en utilisant le SqlAdapter généré par Visual Studio:
private void Button1_Click( object sender, System.EventArgs e)
{
sqlSelectCommand1.Parameters["@Beginning_Date"].Value = Calendar1.SelectedDate;
sqlSelectCommand1.Parameters["@Ending_Date"].Value = Calendar2.SelectedDate;
DataSet DS = new DataSet();
sqlDataAdapter1.Fill(DS, "Sales");
DataGrid1.DataSource = DS.Tables["Sales"].DefaultView;
DataGrid1.DataBind();
}
|
Dans l’évènement « Page_Load », sélectionner deux dates utilisables pour l’appel de la procédure stockée :
Private Sub Page_Load( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Calendar1.SelectedDate = New Date(1996, 12, 6)
Calendar1.VisibleDate = Calendar1.SelectedDate
Calendar2.SelectedDate = New Date(1997, 1, 18)
Calendar2.VisibleDate = Calendar2.SelectedDate
End Sub |
Et en C#
private void Page_Load( object sender, System.EventArgs e)
{
Calendar1.SelectedDate = new DateTime(1996, 12, 6);
Calendar1.VisibleDate = Calendar1.SelectedDate;
Calendar2.SelectedDate = new DateTime(1997, 1, 18);
Calendar2.VisibleDate = Calendar2.SelectedDate;
} |
- Compiler et naviguer sur la page « DataGridProcedure »