Transcript
Accès aux données : ADO.NET
Objectif
Maîtriser l’accès aux bases de données, en utilisant les objets ADO.net
Mode d’emploi
Pour chacun des thèmes abordés, ce support de formation :
présente les points essentiels
renvoie à des supports de cours, des livres ou à la documentation en ligne du constructeur, par le symbole : ??
propose des exercices pratiques par le symbole : ?
Autres symboles utilisés :
??
Point important qui mérite d’être souligné
?
A éviter à tout prix !
?
Manipulation à réaliser avec un utilitaire graphique (qui devrait normalement simplifier le travail !)
?
Approfondissement : travail de documentation ou exercice supplémentaire, à faire individuellement (non intégré dans le temps de formation moyen)
Lectures conseillées
Manuel de référence Microsoft ADO. NET, de David Sceppa
La documentation en ligne de VB .NET (très détaillée, et en français). Nous indiquerons à chaque chapitre les recherches à effectuer dans l’index.
Outils de développement
Visual Studio .net
Microsoft SQL server
Sommaire
1 Presentation generale d’ADO .NET 6
1.1 Quelques mots sur l’architecture .NET de Microsoft 6
1.2 Le modèle objet d’ADO .NET 7
1.3 Les objets du Fournisseur de données 8
1.4 Les objets du DataSet 8
2 L’acces aux données en mode connecté 9
2.1 La connexion ado .net 9
2.1.1 Créer une connexion par code 9
2.1.2 Quelques propriétés et méthodes de l’objet SqlConnection 10
2.1.3 Créer et configurer une connexion avec l’assistant 10
2.1.4 Accéder aux données, par l’explorateur de serveurs 11
2.2 La commande ado .net 12
2.2.1 Création et initialisation d’une commande par code 12
2.2.2 Quelques propriétés et méthodes de l’objet Command 13
2.2.3 Requêtes de mise à jour 13
2.2.4 Requêtes paramétrées 15
2.2.4.1 Utilisation des commandes paramétrées, par code 15
2.2.4.2 Quelques propriétés et méthodes des paramètres 16
2.2.4.3 Création d’une commande paramétrée, avec l’assistant 16
2.2.5 Requête de type SELECT 17
2.2.5.1 Exécution d’une commande par ExecuteScalar() 17
2.2.5.2 Exécution d’une commande par ExecuteReader() 18
2.2.5.3 Quelques propriétés et méthodes de l’objet DataReader 19
2.3 Les transactions 21
2.3.1 La gestion des transactions 21
2.3.2 Quelques propriétés et méthodes de l’objet Transaction 22
2.4 L’utilisation des procédures stockées 23
2.4.1 Appel de la procédure stockée 23
2.4.2 Récupération des résultats de la procédure stockée 23
2.4.3 Procédure stockée et gestion des transactions 24
3 L’ACCES AUX données en Mode déconnecté 25
3.1 Le DataSet 25
3.1.1 Quelques propriétés et méthodes des objets DataSet et DataTable 26
3.2 Le DataAdapter 26
3.2.1 Quelques propriétés et méthodes de l’objet DataAdapter 27
3.3 Utilisation du DataSet et du DataAdapter par code 28
3.4 Utilisation du DataSet à l’aide de l’assistant 30
3.5 les controles liés 32
3.5.1 Le DataBinding 32
3.5.2 Les DataGrids 33
3.5.3 Les ComboBox et les ListBox 35
3.6 Les mises a jour via les datasets 37
4 Les reports 39
4.1 Création d’un Report 39
4.2 Exécution du report 40
Presentation generale d’ADO .NET
Dans la plupart des applications informatiques actuelles, il est indispensable d’accéder en lecture ou en mise à jour à des bases de données, locales ou distantes. Ce document montre comment utiliser Visual Studio .NET pour accéder aux données et pour les présenter à l’utilisateur.
Quelques mots sur l’architecture .NET de Microsoft
Visual Studio .NET est une plate-forme de développement d’applications graphiques, multilangages (Visual Basic .NET, C# etc..). Tous les exemples de ce document sont écrits en VB .Net mais peuvent facilement être transposés dans n’importe quel langage de la plate-forme.
Visual Studio .NET possède un modèle objet appelé ADO .NET (ActiveX Data Object .NET), qui permet de se connecter à de nombreuses bases de données relationnelles. Le même modèle est utilisable dans des applications client-serveur classiques écrites en VB .NET et dans des applications Web basées sur ASP .NET (Active Server Page .NET).
3798570128206500
2349502577465Système d’exploitation
00Système d’exploitation
1943100180340Client (VB .NET )
00Client (VB .NET )
Common Language Runtime
Bibliothèque de classes communes (Framework .NET)
IHM Données
ADO.NET
Common Language Runtime
Bibliothèque de classes communes (Framework .NET)
IHM Données
ADO.NET
234950180340WEB (ASP.NET)
00WEB (ASP.NET)
ADO .NET fait partie d’une bibliothèque de classes (le Framework) qui peut fonctionner sur plusieurs architectures : PC de bureau, Téléphones portables, Pocket PC. Toutes les classes du Framework s’appuient sur une couche logicielle, la CLR (Common Language Runtime) qui les interface avec les différents systèmes d’exploitation. La CLR est l’équivalent dans le monde Microsoft, de la machine virtuelle Java.
Le modèle objet d’ADO .NET
ADO .NET permet de travailler en deux modes :
« connecté » : le poste client maintient une « connexion » réseau avec le serveur, et lui envoie des requêtes pour lire ou écrire directement dans la base de données distante ;
« déconnecté » : le poste client effectue une copie locale des données en mémoire, dans un DataSet (groupe de données). Le DataSet contient des tables qui permettent de copier et d’organiser les données sur le poste client.
4773295203327000
1828800166243000
ADO.NET distingue :
La communication avec la base de données, qui s’effectue par un Fournisseur de données (Data Provider). Il existe des fournisseurs génériques (préfixes OleDb, Odbc) qui sont reconnus par la plupart des bases de données, et quelques fournisseurs spécialisés pour un SGBD donné (préfixes sql pour SqlServer, oracle pour Oracle). Dans ce document, nous prendrons toujours comme exemple le fournisseur d’accès pour SqlServer.
La manipulation locale des données, que l’on peut recopier dans un DataSet
Les objets du Fournisseur de données
L’objet Connection permet de se connecter à une base de données en donnant le nom du serveur, de la base, et le nom et le mot de passe d’un utilisateur connu du SGDB. En utilisant l’objet Connection, votre programme effectue la même opération vis-à-vis du serveur que la phase de connexion de l’utilisateur dans « L’Analyseur de requêtes ».
L'objet Command permet d’envoyer à la base de données, des requêtes SQL d’interrogation ou de modification, avec ou sans paramètres. L’objet Command contient une collection Parameters qui permet de passer des paramètres en entrée à la requête avant son exécution sur le serveur, et de récupérer des paramètres de sortie après exécution. A noter que l’objet Command permet également d’exécuter des procédures stockées sur le serveur, et de récupérer leur valeur de retour.
Pour les requêtes qui renvoient des données (SELECT), on peut récupérer directement ces données en mode connecté grâce au DataReader : cet objet simple permet de lire séquentiellement les lignes sélectionnées par le SELECT, sans pouvoir les modifier ou revenir en arrière.
L’objet DataAdapter est le support du mode « déconnecté ». Il est plus élaboré que le DataReader et contient quatre commandes, correspondant aux quatre instructions SQL de base : SELECT, UPDATE, INSERT, DELETE. Il permet de remplir le DataSet, grâce à sa requête SELECT, et éventuellement de répercuter des mises à jour du DataSet vers la base de données via les requêtes UPDATE, INSERT et DELETE.
Les objets du DataSet
Le DataSet stocke une copie des données en mode déconnecté, indépendamment de toute base de données : on peut le remplir localement avec des tableaux, des collections. Il peut être utilisé avec plusieurs bases de données, ou des fichiers XML.
Le DataSet constitue à lui seul une petite base de données relationnelles en mémoire. Il contient une ou plusieurs tables (collection d'un ou plusieurs objets DataTable) constituées de lignes (DataRowCollection) et de colonnes (DataColumnCollection), et éventuellement des définitions de contraintes d’intégrité (clés primaires et clés étrangères).
L’acces aux données en mode connecté
La connexion ado .net
Créer une connexion par code
a) Importer dans votre programme l’espace de noms System.Data.SqlClient qui contient le fournisseur de données pour SqlServer, ou System.Data.OleDb pour le fournisseur générique OleDb, ou System.Data.Odbc pour le fournisseur générique Odbc :
Imports System.Data
Imports System.Data.SqlClient
b) Créer une instance de la classe SqlConnection, en passant une chaîne de connexion à son constructeur :
Dim co as SqlConnection
co = New SqlConnection("server=SERVEUR-CR;Initial Catalog=BanqueDémo;
User Id=stage;Password=stage;")
Syntaxe de la chaîne de connexion :
server : nom du serveur Sql Server
Initial Catalog : nom de la base de données
User Id : nom de l’utilisateur déclaré dans Sql Server
Password : mot de passe de l’utilisateur
On peut aussi créer la connexion avec le constructeur non paramétré, et renseigner sa propriété ConnexionString
Dim co SqlConnection
co = New SqlConnection
co.ConnectionString = "server=SERVEUR-CR;Initial Catalog=BanqueDémo;
User Id=stage;Password=stage;"
c) Ouvrir la connexion
co.Open()
Jusqu’ici, VB .NET a seulement préparé un objet en mémoire, sans effectuer aucune vérification. C’est à l’ouverture qu’il recherche le serveur sur le réseau, et l’interroge pour vérifier le nom de l’utilisateur et son mot de passe. Si la chaîne de connexion est erronée, le fournisseur de données génère une exception de la classe SqlException : par exemple,
« SQL Server n’existe pas ou l’accès est refusé ».
Documentation .Net (index) : Connection (objet) / Connexion à une source de données à l’aide de ADO .NET
Quelques propriétés et méthodes de l’objet SqlConnection
Méthodes publiques
Méthode
Description
Open
Ouvre la connexion vers une base de données avec les paramètres
spécifiés dans la propriété ConnectionString.
Close
Ferme la connexion.
BeginTransaction
Lance une nouvelle transaction, en créant un objet de la classe
SqlTransaction qui fournit les méthodes commit et rollback
CreateCommand
Crée et retourne un objet SqlCommand associé à SqlConnection
ChangeDatabase
Modifie la base de données en cours d'un SqlConnection ouvert.
Propriétés publiques
Propriété
Description
ConnectionString
pour définir la connexion à une source de données : serveur, base de données, utilisateur….
State
Obtient l'état actuel de la connexion.
Database
Obtient le nom de la base de données en cours ou de la base de données à utiliser une fois la connexion ouverte
CommandTimeout
Nombre de secondes d'attente avant de renvoyer une
erreur, suite à une tentative d'exécution d'une commande
WorkstationId
Chaîne qui identifie le client de la base de données. S'il n'est pas spécifié, nom de l'ordinateur client.
Documentation .Net (index) : SqlConnection
Créer et configurer une connexion avec l’assistant
??Dans la boîte à outils, choisir un objet connexion : par exemple SqlConnection pour une connexion vers SqlServer.
Dans la propriété ConnectionString, choisir Nouvelle connexion… et configurer la connexion grâce à l’assistant Propriétés des liaisons de données : nom du serveur, nom de l’utilisateur, mot de passe, base de données sur le serveur.
Toujours Tester la connexion avant de valider
11430003810000
Utiliser la connexion pour accéder aux données, par l’explorateur de serveurs
Pour travailler en client-serveur, nous avons besoin de visualiser les tables et leur contenu, indépendamment du programme en cours de développement
??Ceci peut se faire par n’importe quel client : Analyseur de requêtes, Enterprise Manager mais aussi directement dans Visual Studio .NET, par l’explorateur de serveurs. Cette méthode permet de tester la nouvelle connexion, et de vérifier les droits de l’utilisateur sur les tables.
125730012954000
La commande ado .net
Création et initialisation d’une commande par code
Selon le fournisseur de données choisi, on utilisera la classe OleDb.OleDbCommand ou SqlClient.SqlCommand.
Une commande doit toujours être reliée à une connexion, soit lors de son instanciation, soit en affectant sa propriété Connection. Il faut bien sûr ouvrir cette connexion, avant d’exécuter la commande.
Il existe trois types de commandes, qui permettent soit d’exécuter une procédure stockée, soit de récupérer le contenu d’une table entière, soit d’exécuter une requête SQL. Le type d’une commande est fixé par la propriété CommandType :
procédure stockée -> StoredProcedure
table entière -> TableDirect
requête (par défaut) -> Text
L’énoncé de la commande – nom de procédure, de table ou chaîne de requête selon le cas - est renseigné par sa propriété CommandText - ou encore lors de son instanciation lorsqu'il s'agit d'une requête.
Dim commande As SqlCommand
' création d'une nouvelle commande
commande = New SqlCommand
' on rattache la nouvelle commande à la connexion en cours
' (voir création et ouverture de la connexion dans l’extrait précédent)
commande.Connection = co
' type de commande : ici une requête SQL
commande.CommandType = CommandType.Text
' texte de la requête SQL
commande.CommandText = "INSERT Compte (Nom, Prénom, Solde) VALUES ('Lécu', 'Régis', 10000)"
Dans cet exemple, la commande est figée : elle insère dans la base un utilisateur connu à l’avance.
On peut généraliser simplement cette méthode en construisant dynamiquement le texte de la requête SQL, par des concaténations de String :
commande.CommandText = "INSERT Compte (Nom, Prénom, Solde) " + "VALUES ('" + txtNom.Text + "','" + txtPrenom.Text + "'," + txtSolde.Text + ")"
Documentation .Net (index) : SqlCommand
Quelques propriétés et méthodes de l’objet Command
Méthodes publiques
Méthode
Description
CreateParameter
Crée un nouvel objet Paramètre.
ExecuteNonQuery
Exécute la commande et renvoie le nombre de lignes affectées dans le cas de INSERT, UPDATE et DELETE, et renvoie -1 dans le cas de SELECT
ExecuteReader
Exécute la commande et crée un objet DataReader
ExecuteScalar
Exécute la commande et récupère un résultat unique sans créer de jeu de données.
Prepare
Permet de compiler la requête avant de l’exécuter
Propriétés publiques
Propriété
Description
CommandText
Définit le texte de la requête SQL, le nom de la table, ou le nom de la procédure stockée
CommandTimeOut
Définit le temps avant la levée d’une exception, si la commande n’aboutit pas
CommandeType
Type de la commande. Valeurs possibles :
Text : Requête SQL
StoredProc : Procédure stockée
TableDirect :Table (cette valeur n’existe que pour OleDbCommand)
Connection
Renvoie ou définit la connexion sur laquelle la commande est définie
Transaction
Renvoie ou définit la transaction à laquelle appartient la commande
Parameters
Renvoie la collection des objets Parameters d’une commande
Requêtes de mise à jour
Cette méthode de l’objet commande permet d’exécuter des requêtes SQL de type UPDATE, INSERT ou DELETE qui ne renvoient pas de lignes au poste client.
La valeur de retour donne le nombre de lignes affectées par la requête.
Il faut penser à gérer les exceptions renvoyées par le serveur : dans cet exemple, on affiche le message de l’exception (ex.Message).
' voir création de la commande dans l’extrait précédent
Try
' on soumet la commande au serveur, sans interrogation.
' La méthode retourne le nombre de lignes affectées
Dim nblignes As Integer
nblignes = commande.ExecuteNonQuery()
Catch ex As Exception
MsgBox("Erreur insertion : " + ex.Message, MsgBoxStyle.Critical, Me.Text)
End Try
?? EXERCICE 1 Nous allons, pour découvrir ADO.net, concevoir et réaliser une application bancaire de gestion des comptes courants. On ne gèrera pas les problèmes liés aux virements inter banques.
La base de données sera gérée sur SQL-SERVER
La structure de la base est la suivante :
571500109220COMPTE
NumCompte
Nom
Prenom
Solde
00COMPTE
NumCompte
Nom
Prenom
Solde
239268031750Débiter
00Débiter
MCD :
1485900628650,n
000,n
3771900628651,1
001,1
411480062865VIREMENT
NumVirement
Montant
DateVir
00VIREMENT
NumVirement
Montant
DateVir
33089851454150014782805016500
3308985984250014782809842500
1485900381000,n
000,n
3771900381001,1
001,1
2392680120650Créditer
00Créditer
MLD :
COMPTE (NumCompte, Nom, Prenom, Solde)
VIREMENT (NumVirement, NumCompteDebit, NumCompteCredit, Montant, Datevir)
NumCompte sera un numéro automatique.
Solde est initialisé par défaut à zéro.
Datevir est par défaut la date du jour.
NumCheque n’est pas en numéro automatique.
?? EXERCICE 2 :
Créer une feuille permettant de saisir un nouveau compte.
13716008890000
Contrôler avant soumission que tous les champs sont remplis
Se connecter à la base
Exécuter la commande d’insertion
Se déconnecter
Gérer une éventuelle exception.
Dans cette première version de l’exercice, vous créerez par code les objets SqlConnection et SqlCommand.
Requêtes paramétrées
Utilisation des commandes paramétrées, par code
La méthode précédente par concaténation de String devient vite fastidieuse, pour des cas compliqués
La classe SqlCommand permet de construire des requêtes paramétrées. Dans le texte de la commande (CommandText), les paramètres sont désignés par un nom quelconque précédé du caractère @ (@num dans l’exemple suivant)
' Créer la commande RQInit, en passant la requête SQL à son constructeur
Dim RQInit as SqlCommand
RQInit = New SqlCommand("Update Compte Set solde=0 WHERE numCompte=@num")
Les objets de la classe SqlCommand possèdent une propriété Parameters qui permet de déclarer les paramètres utilisés dans le texte de la commande. Chaque paramètre est lui-même un objet de la classe SqlParameter qui doit être créé, initialisé et ajouté à la collection Parameters de la commande.
' définir les paramètres en entrée de la commande : ici le numéro de compte
RQInit.Parameters.Add ( New SqlParameter("@num", SqlDbType.Int, 4) )
Dans cet exemple, on crée un seul paramètre de nom @num, de type SQL SqlDbType.Int, de taille 4.
Avant de lancer la commande, il faut renseigner tous les paramètres en entrée. On accède aux paramètres, dans la collection Parameters, soit par leur nom ( @num), soit par leur indice ( 0 )
RQInit.Parameters ("@num").Value = Cint(txtNum.Text)
' on lance la commande paramétrée
RQInit.ExecuteNonQuery()
Documentation .Net (index) : SqlParameter
SqlCommand : propriété Parameters
Quelques propriétés et méthodes des paramètres
Méthodes publiques de la collection Parameters
Méthode
Description
Add
Permet d’ajouter un nouveau paramètre à la collection. Par ex :
commande.Parameters.Add ( New SqlParameter("@num", SqlDbType.Int, 4)
Propriétés publiques de l’objet Parameter
Propriété
Description
DBType
Définit le type du paramètre.
Direction
Prend l’une des valeurs suivantes :
Input : paramètre d’entrée
InputOutput : paramètre d’entrée sortie
Output : paramètre de sortie
ReturnValue : représente un code retour
Création d’une commande paramétrée, avec l’assistant
?? On peut aussi utiliser l’assistant pour créer des commandes paramétrées.
Dans la boîte à outils, choisir un objet commande : par exemple SqlCommand pour une connexion vers SqlServer (ou OdbcCommand, OleDbCommand). Dans les propriétés de la commande ainsi créée, on peut définir la propriété CommandText, avec une requête, éventuellement paramétrée. Dans ce cas, on peut indiquer les paramètres utilisés à l’aide de la propriété Parameters
22860012573000
?? EXERCICE 2bis ;
Refaire l’exercice précédent en créant par la boîte à outils les objets SQLConnection et SQLCommand ; utiliser une requête insert paramétrée.
Requête de type SELECT
Le jeu d'enregistrements récupéré suite à l'exécution d'un "select" d'une requête ou procédure stockée s'exploite de 2 façons:
Soit en mode connecté, ligne par ligne, grâce à un objet DataReader permettant un accès en lecture seule et en mode séquentiel, comme sur un flux classique. Ce mode a l'avantage de décharger la mémoire puisqu'il ne stocke qu'une ligne à la fois, mais il oblige à garder la connexion ouverte tout le long de son exploitation.
Soit en mode déconnecté, grâce à un objet DataSet qui est un cache en mémoire des données extraites de la source de données, et qui facilite le travail grâce à des tables qu’il fabrique avec des données provenant de sources disparates.. Ce mode de connexion est rapide et permet de fermer la connexion, donc de libérer la base.
C’est le mode connecté que nous allons étudier dans un premier temps.
Exécution d’une commande par ExecuteScalar()
Cette méthode de l’objet commande permet d’exécuter des requêtes SQL de type SELECT qui renvoient un résultat unique au poste client. La méthode renvoie la première colonne de la première ligne du jeu de résultats retourné par la requête.
Dim commande As SqlCommand
Dim solde As Object ' objet retourné par ExecuteScalar
Try
' création d'une nouvelle commande
commande = New SqlCommand
' on rattache la nouvelle commande à la connexion en cours
commande.Connection = co
' type de commande : ici une requête SQL
commande.CommandType = CommandType.Text
' texte de la requête SQL
commande.CommandText = "SELECT solde FROM Compte WHERE NumCompte= " + txtNum.Text
' on soumet la commande au serveur : ExecuteScalar renvoie la première colonne de la première ligne envoyée par le serveur
solde = commande.ExecuteScalar()
...
Exécution d’une commande par ExecuteReader()
Cette méthode de l’objet commande permet d’exécuter des requêtes SQL de type SELECT qui renvoient des lignes au poste client.
Attention : Les lignes renvoyées peuvent être accédées en lecture seule et en mode séquentiel (en avant seulement)
Il faut d’abord créer une commande (soit par code, soit en utilisant l’assistant) - pour cela voir chapitre précédent -.
On exécute ensuite la commande en récupérant le résultat dans un SqlDataReader en appelant commande.ExecuteReader().
On peut ensuite utiliser la méthode Read() de l'objet DataReader pour obtenir une ligne de résultats de la requête. La méthode Read() renvoie false lorsque l’on est en fin de DataReader.
??Pendant l'utilisation de SqlDataReader, la connexion associée est occupée à prendre en charge le SqlDataReader et aucune autre opération ne peut être effectuée sur cette connexion en dehors de sa fermeture. Cette situation subsiste jusqu'à ce que la méthode Close du SqlDataReader soit appelée.
On navigue à l’intérieur d’un DataReader à l’aide de la méthode Read(). On peut accéder à chaque colonne de la ligne retournée de différentes manières : en passant le nom ou la référence ordinale de la colonne au DataReader. Cependant, pour une meilleure performance, le DataReader fournit une série de méthodes qui vous permettent d'accéder aux valeurs de colonnes dans leurs types de données natifs (GetDateTime, GetDouble, GetGuid, GetInt32, etc.).
Par exemple :
Rd("Montant") ' Toutes ces commandes
Rd(0) ' font référence au même
Rd.Item("Montant") ' champ
Rd.Item(0)
Rd.GetDouble("Montant")
Rd.GetDouble(0)
Si plusieurs jeux de résultats sont retournés (cas ou plusieurs requêtes sont exécutées à la suite), on peut naviguer entre les différents jeux de résultats à l’aide de la méthode NextResult.
'création de la requête
Dim req As String
req = "SELECT * from personne where nom = " & txtnom.Text
Dim com As SqlCommand = New SqlCommand(req, con)
'exécution de la commande; le résultat est récupéré dans le
'DataReader rd qu’il faut ensuite balayer
Dim rd As SqlDataReader = com.ExecuteReader()
'personne inexistante
If rd.Read() = False Then
MessageBox.Show("personne inexistant", "Erreur")
Else
'affichage des infos personne
txtnom.Text = rd(1)
txtprenom.Text = rd(2)
txtadresse.Text = rd(3)
End If
...
Documentation .Net (index) : SqlDataReader, DataReader
Quelques propriétés et méthodes de l’objet DataReader
Méthodes publiques
Méthode
Description
Close
Ferme le DataReader.
GetDateTime, GetDouble, GetBoolean…..
Renvoie la valeur d’une colonne sous la forme d’une donnée typée. On utilise la méthode IsDbNull avant, pour vérifier que la colonne n’est pas nulle.
GetSchemaTable
Permet de récupérer les informations des colonnes (schéma des données) dans un objet DataTable.
IsDbNull
Renvoie vrai si la donnée est nulle.
NextResult
Permet de changer de jeu d’enregistrements (dans le cas où l’on a plusieurs jeux d’enregistrements, issus de plusieurs requêtes qui s’exécutent à la suite)
Read
Se positionne sur l’enregistrement suivant. Renvoie True s’il existe une ligne suivante, False sinon. Ne fait pas la récupération des valeurs. Au début (à la création du DataReader), on est positionné avant le premier enregistrement. Il faut donc faire un Read.
Propriétés publiques
Propriété
Description
FieldCount
Renvoie le nombre de colonnes présentes dans la ligne en cours
HasRow
Renvoie vrai si le jeu d’enregistrements contient au moins une ligne
IsClosed
Renvoie vrai si l’objet est fermé
Item
Renvoie la valeur de la colonne. On peut identifier la colonne par son nom ou par sa position ordinale. On peut omettre la propriété item. (Rd.Item(“montant”), Rd.Item(0) et Rd(0) sont équivalentes)
?? EXERCICE 3 :
Afficher (par code) les détails d’un compte de numéro donné. Ce numéro sera saisi dans un champ texte.
80010010858500
Avant soumission, vérifier que le numéro saisi est un entier valide
Gérer une éventuelle non existence du compte
?? EXERCICE 3bis ;
Refaire l’exercice précédent en créant par la boîte à outils les objets SQLConnection et SQLCommand.
Les transactions
La gestion des transactions
Les transactions ont pour objectif de garantir l’intégrité des données. Vous avez déjà vu le principe de fonctionnement des transactions (Cf. cours SQL), ainsi que les différentes techniques à mettre en œuvre.
Ces principes doivent être appliqués aussi depuis une application VB.Net qui met à jour des données.
Voici une portion de code qui montre comment tout cela s'organise :
Try
'ouverture transaction
tr = con.BeginTransaction()
Dim req As String
req = "UPDATE ... "
Dim com As SqlCommand = New SqlCommand(req, con)
'on precise que cette commande est associée à la transaction
com.Transaction = tr
'ensuite on exécute la requete
com.ExecuteNonQuery()
'on fait un commit si tout se passe bien
tr.Commit()
Catch ex As Exception
MessageBox.Show(Err.Description, "Erreur")
'on fait un rollback en cas d’erreur
if not isNothing(tr) Then
tr.Rollback()
end if
End Try
Nous validons les modifications avec Commit, à condition qu'aucune des requêtes ne renvoie d'erreur. Si l'une échoue, nous abandonnons les mises à jour avec Rollback. On remarquera l'utilisation du test permettant de savoir si une transaction est ouverte avant de faire le Rollback … En effet, lorsque l’on va en erreur, on n’a peut être pas encore ouvert la transaction; dans ce cas, il ne faut pas faire de Rollback sous peine de plantage…
Documentation .Net (index) : Transaction (objet)
Quelques propriétés et méthodes de l’objet Transaction
Méthodes publiques
Méthode
Description
Commit
Valide la totalité de la transaction
Rollback
Annule la transaction jusqu’au dernier état stable (soit la création de la transaction, soit le dernier point Save défini).
Save
Crée un point intermédiaire d’enregistrement de la transaction.
Propriétés publiques
Propriété
Description
Connection
Renvoie la connexion à laquelle est associée la transaction
IsolationLevel
Spécifie le niveau d’isolation de cette transaction
?? EXERCICE 4 ;
Compléter l’écran précédent pour gérer les dépôts d’espèces et les retraits
6858006667500
Avant soumission vérifier que le montant est un décimal valide
Mettre en place une transaction pour :
Vérifier le solde avant opération,
Exécuter l’opération,
En cas d’exception faire un rollback et signaler l’erreur.
Faire 2 versions de cet exercice : en créant par code, et à l’aide de la boîte à outils, les objets
SQLConnection et SQLCommand.
L’utilisation des procédures stockées
Appel de la procédure stockée
Une procédure stockée est un groupe d'instructions Transact-SQL qui est compilé une fois pour toutes et peut être exécuté plusieurs fois. La procédure accepte des paramètres d'entrée et renvoie plusieurs valeurs sous forme de paramètres de sortie et/ou de code retour.
ADO.NET permet d'appeler ces procédures au moyen de l'objet Command, dont la propriété .CommandType sera alors mise à la valeur "StoredProcedure " et dont la propriété .CommandText contiendra le nom de la procédure à invoquer.
Avant d'appeler la procédure stockée par la méthode ExecuteNonQuery(), il faut initialiser ses paramètres en entrée (collection Parameters de l'objet Command) : chaque commande possède une collection Parameters de paramètres (de types OleDbParameter ou SqlParameter) que l'on peut définir ou lire individuellement pour passer ou recevoir des valeurs.
' on renseigne les paramètres en entrée de la procédure stockée
PSRetrait.Parameters("@NumCompte").Value = txtNumCompte.Text
PSRetrait.Parameters("@Montant").Value = txtMontant.Text
Récupération des résultats de la procédure stockée
Pour les paramètres autres que Input, vous devez définir la propriété ParameterDirection pour spécifier si le type de paramètre est InputOutput, Output ou ReturnValue.
Après exécution, on récupère la valeur de retour et les paramètres en sortie de la procédure dans la collection Parameters
Try
' on lance la procédure stockée (ExecuteNonQuery pour les
procédures qui ne renvoient pas d'informations par des SELECT)
PSRetrait.ExecuteNonQuery()
' on récupère la valeur de retour @return_value
Dim cr As Integer
cr = PSRetrait.Parameters("@return_value").Value
' si le compte rendu est OK, on récupère le paramètre en sortie
If cr = 0 Then
txtSolde.Text = PSRetrait.Parameters("@NouveauSolde").Value
' sinon on affiche le message d'erreur
Else
AfficherErreur(cr)
End If
Catch ex As Exception
MsgBox("Appel procédure stockée : " + ex.Message,
MsgBoxStyle.Critical, Me.Text)
End Try
Procédure stockée et gestion des transactions
Lorsque l’on encapsule la gestion des transactions dans une procédure stockée, et si l’on a une exception lors de l'exécution de cette procédure, la transaction risque de rester ouverte. Il faut alors la fermer depuis VB.Net, dans la gestion des exceptions (dans le catch..), en allant exécuter une requête qui va vérifier si une transaction est ouverte et, si oui, qui fait un rollback.
' Procédure stockée de vérification, en Transac SQL
if @@TRANCOUNT>0
rollback transaction
return (0)
?? EXERCICE 5 :
Construire une nouvelle feuille permettant de saisir et valider un virement de compte à
compte.
- Saisir séparément chaque numéro de compte et la clé. La clé n’est pas un champ de la
table compte, c’est le reste de la division par 7 du numéro de compte.
- Les boutons « valider », après saisie du numéro de compte (débiteur ou créditeur),
vérifient que la clé correspondante est cohérente avec le numéro de compte, vérifient
l’existence du compte, et affichent le nom du client correspondant pour un contrôle
visuel.
- Dès que le numéro (ou la clé) est modifié(e), les champs nom et prénom sont effacés.
- Effectuer les contrôles : le virement n’est possible que si débiteur et créditeur ont été
validés, le numéro de virement doit être un entier valide et ne doit pas déjà exister, et le
montant doit être un décimal valide.
- Faire le traitement dans une procédure stockée bien protégée, avec code retour et
sécuriser le virement dans une transaction, annuler en cas d’incident.
- Tester en simulant un crash entre les deux mises à jour (débit et crédit).
571500825500
L’ACCES AUX données en Mode déconnecté
Le DataSet
Un DataSet (ou groupe de données) est un cache en mémoire qui représente un jeu de données composé de plusieurs tables, de relations entre les différentes tables, et de contraintes qui s’appliquent aux données. Ce cache est déconnecté de la source de données.
Plusieurs cas d’utilisation d’un DataSet peuvent être envisagés :
Il peut être utilisé pour gérer des données locales à l’application : dans ce cas, on peut créer des DataTables, DataRelations et Constraints dans un DataSet et remplir les tables de données par programme.
Il peut être rempli à partir d’une ou plusieurs sources de données existantes : dans ce cas on utilise un DataAdapter pour remplir les différentes tables.
Il peut être rempli à partir de données XML.
Étant donné que le DataSet est indépendant de la source de données, il peut inclure des données locales par rapport à l'application ainsi que des données provenant de plusieurs sources. L'interaction avec les sources de données existantes est contrôlée par le DataAdapter
Un conseil : essayez toujours de limiter au maximum la taille d'un groupe de données en le remplissant uniquement avec les enregistrements dont vous avez besoin.
Les DataSets utilisent le modèle objet suivant :
26289001270000
Modèle d'objet DataSet
Pour simplifier, un DataSet est composé d'une collection de tables (sa propriété .Tables), chaque table (objet de type DataTable) étant elle même composée d'une collection de colonnes (sa propriété .Columns) pour son schéma (objets de type DataColumn) et de lignes (sa propriété .Rows) pour son contenu (objets de type DataRow).
Documentation .Net (index) : DataSet
Quelques propriétés et méthodes des objets DataSet et DataTable
Méthodes publiques de l’objet DataSet
Méthode
Description
AcceptChanges
Valide toutes les modifications en cours (méthode existant aussi pour les objets DataTable et DataRow). Bascule toutes les lignes de toutes les tables vers l’état ‘Unchanged’
Clear
Supprime toutes les lignes de toutes les tables du DataSet. A faire avant de recharger un DataSet.
Merge
Permet de fusionner deux DataSet
Reset
Réinitialise le DataSet dans son état d’origine
Propriétés publiques de l’objet DataSet
Propriété
Description
Relations
Obtient la collection des relations qui relient les tables et permettent de naviguer entre tables.
Tables
Obtient la collection des tables contenues dans le DataSet.
Méthodes publiques de l’objet DataTableCollection
Méthode
Description
Add
Ajoute une table à la collection des tables du DataSet
Propriétés publiques de l’objet DataTable
Propriété
Description
Columns
Obtient la collection des colonnes de la table.
Constraints
Obtient la collection des contraintes de la table
PrimaryKey
Renvoie un tableau d’objets DataColumn qui contient la ou les colonnes composant la clé primaire de la table.
Rows
Obtient la collection des lignes de la table
Le DataAdapter
Chaque fournisseur de données .NET Framework fourni avec le .NET Framework dispose d'un objet DataAdapter : (OleDbDataAdapter, SqlDataAdapter ou OdbcDataAdapter).
Un DataAdapter est utilisé pour extraire les données d'une source de données et remplir les tables dans un DataSet. Le DataAdapter répercute aussi les modifications apportées au DataSet dans la source de données.
Le DataAdapter utilise l'objet Connection du fournisseur de données .NET Framework pour se connecter à une source de données, et les objets Command pour extraire les données de la source et y répercuter les modifications.
La propriété SelectCommand du DataAdapter est un objet Command qui extrait les données de la source de données. On peut aussi passer directement en paramètre la commande qui va permettre
d’extraire les données. Les propriétés InsertCommand, UpdateCommand et DeleteCommand du DataAdapter sont des objets Command qui gèrent les mises à jour dans la source de données conformément aux modifications faites dans le DataSet.
La méthode Fill du DataAdapter est utilisée pour remplir un DataSet avec les résultats de SelectCommand du DataAdapter. Fill prend comme arguments un DataSet à remplir et un objet DataTable ou le nom du DataTable à remplir avec les lignes retournées par SelectCommand.
Remarque : la méthode Fill ouvre automatiquement la connexion que le DataAdapter utilise, si la connexion n'est pas déjà ouverte. Dans ce cas, la connexion sera automatiquement fermée lorsque le Fill est terminé. Si l’on veut garder la connexion ouverte pendant plusieurs opérations (pour améliorer les performances de l’application), il faut appeler de manière explicite la méthode Open de la connexion, effectuer les opérations sur la source de données puis appeler la méthode Close de la connexion.
Documentation .Net (index) : DataAdapter
Quelques propriétés et méthodes de l’objet DataAdapter
Méthodes publiques
Méthode
Description
Fill
Permet de récupérer des données vers un DataSet. La valeur retournée est le nombre de lignes rapatriées. Cette méthode utilise l’objet Command du DataAdapter défini dans la propriété SelectCommand. Si la connexion est fermée, le DataAdapter l’ouvre le temps du rapatriement des données, puis la referme. Si plusieurs jeux d’enregistrements sont rapatriés, il est créé autant de tables que de jeux.
GetFillParameters
Permet de récupérer les paramètres de la requête Select définie dans la propriété SelectCommand.
Update
Cette méthode déclenche l’envoi des modifications faites dans le DataSet vers la source de données. Elle renvoie le nombre de lignes modifiées. Lors de l’appel de la méthode ‘Update’, le DataAdapter regarde la propriété ‘RowState’ de chaque ligne et tente de répercuter les modifications des lignes qui ne sont pas à ‘Unchanged’.
Pour chaque ligne, la commande concernée (InsertCommand, DeleteCommand ou UpdateCommand) sera exécutée. Ces commandes peuvent être définies par le programmeur. Si elles ne sont pas définies, et si la commande concerne une table unique, l’objet CommandBuilder va générer automatiquement ces commandes à partir de la commande SelectCommand.
Propriétés publiques
Propriété
Description
DeleteCommand
Obtient ou définit une requête ou une procédure stockée pour supprimer un enregistrement dans la source de données.
InsertCommand
Obtient ou définit une requête ou une procédure stockée pour créer un enregistrement dans la source de données.
SelectCommand
Obtient ou définit une requête ou une procédure stockée permettant de rapatrier des données dans le DataSet
UpdateCommand
Obtient ou définit une requête ou une procédure stockée pour mettre à jour des enregistrements dans la source de données.
Utilisation du DataSet et du DataAdapter par code
On va commencer par créer le DataSet et le DataAdapter. Pour cela, on crée une commande associée à la requête que l’on veut exécuter, et on crée un DataAdapter qui reçoit en paramètre la commande créée. Tout ceci peut s’effectuer une seule fois (dans le load de la feuille par exemple).
' Apres avoir créé une connection, création d'une nouvelle commande
commande = New SqlCommand
' on rattache la nouvelle commande à la connexion en cours
commande.Connection = maConnexion
' type de commande : ici une requête SQL
commande.CommandType = CommandType.Text
' texte de la commande SQL : sélection sur toute la table
commande.CommandText = "SELECT * FROM Compte"
' création du Data Adapter : sert de lien entre le Data Set et le
' serveur
' Le Data Adapter reçoit en paramètre la commande qui va permettre
' de rapatrier les données du serveur
monDataAdapter = New SqlDataAdapter(commande)
' création du Data Set : réservoir local de données en mémoire
monDataSet = New DataSet
On va ensuite charger le DataSet. Le chargement du DataSet se fait par la méthode Fill() du DataAdapter : on charge une table du DataSet ; il faut nommer cette table (ici, "mesComptes"). Attention, avant de rafraîchir le DataSet, il faut le vider à l’aide de la méthode Clear(), sinon les données nouvelles viennent s’ajouter aux données déjà présentes.
' on vide le Data Set
monDataSet.Clear()
' on rafraichit le Data Set grâce au Data Adapter
monDataAdapter.Fill(monDataSet, "mesComptes")
' on affiche le nombre de lignes du Data Set, chargées en local
txtNbFiches.Text = monDataSet.Tables("mesComptes").Rows.Count
...
On va enfin exploiter les données contenues dans le DataSet :
txtNum.Text = monDataSet.Tables("mesComptes").Rows(i).Item("NumCompte")
txtNom.Text = monDataSet.Tables("mesComptes").Rows(i).Item("Nom")
txtSolde.Text = monDataSet.Tables("mesComptes").Rows(i).Item("solde")
Attention, si des colonnes sont facultatives et peuvent contenir une valeur nulle, il faut tester leur contenu en utilisant IsDBNull().
?? EXERCICE 6 :
Construire une nouvelle feuille permettant de lire les comptes existants
- Le bouton charger permet la lecture en mode déconnecté (dans un DataSet) de tous les
comptes, et l’affichage du premier, ainsi que le nombre de comptes.
- Les boutons « premier », « dernier », « suivant », « précédent » permettent de naviguer
dans le DataSet et d’afficher le compte courant. Pensez à désactiver les boutons qui n’ont
pas de raison d’être.
Créer les DataSet et les DataAdapter par code.
102870014541500
Utilisation du DataSet à l’aide de l’assistant
On peut aussi créer le DataSet et le DataAdapter en utilisant les assistants.
On crée la connexion "maConnexion" par l'assistant, et on configure la chaîne de connexion en sélectionnant "connexionString" dans les propriétés.
Ensuite, on crée un Data Adapter en le sélectionnant dans la boîte à outils. L’assistant de configuration d’adaptateur de données se déclenche automatiquement, et va nous permettre de créer la commande associée.
18288007556500
Enfin, on crée le Data Set à partir du Data Adapter, par l'option "Générer le Groupe de données" (click droit sur le DataAdapter).
114300952500
Seuls, le rafraîchissement du DataSet et l’exploitation des données sont à faire par code.
?? EXERCICE 6bis :
Refaire l’exercice précédent en utilisant les assistants.
les controles liés
Le DataBinding
Il est possible d’associer directement des données (issues d’une source de données) à des composants de contrôle Win Forms : c'est le mécanisme du Data Binding. Le lien entre les données et le contrôle est à double sens : les données peuvent être liées à l’une des propriétés du contrôle (pour être affichées par exemple), et les modifications de données peuvent aussi être répercutées dans la source de données.
Il existe des liaisons de données simples où un contrôle est lié à un seul élément de données (c’est le cas des contrôles Text, Label) , et des liaisons de données complexes, où il est possible de lier un contrôle à plusieurs éléments de données (c’est le cas des DataGrid et ListBox, ComboBox…).
Si l’on veut créer une liaison simple avec un contrôle dérivé de la classe System.Windows.Forms.Control (par exemple, les contrôles Label, Button, TextBox, RadioButton …), il faut utiliser la propriété .DataBindings de ce contrôle. Ceci permet d’accéder à la collection des liaisons de données du contrôle. En ajoutant un objet de type Binding à cette collection, on peut lier une propriété du contrôle à une source de données.
Exemple : Pour créer une liaison avec un textBox, dans la feuille de propriété des zones de texte, choisir DataBindings, puis dans Text : on sélectionne le Data Set, la table et la colonne que l'on veut associer à la zone de texte
Attention : en utilisant la feuille de propriété, on ne peut lier des contrôles qu'à des Data Set "Typés" qui possèdent leur schéma XML (par code, tout est possible).
45720035369500
On peut ensuite utiliser par code certaines propriétés intéressantes de l’objet BindingContext de la feuille. Cet objet sert schématiquement à la synchronisation des contrôles dépendants dans un Windows Form qui sont liés à la même source de données:
' pour naviguer dans le DataSet, et se positionner sur une ligne (ici, la première)
Me.BindingContext.Item(monDataSet, "Compte").Position = 0
....
' termine la modification en cours dans le champ texte qui a le focus
Me.BindingContext.Item(monDataSet, "Compte").EndCurrentEdit()
??Attention : l’utilisation du DataBinding pour des contrôles simples (autres que les DataGrids et DataCombos) ne nous paraît guère utile. En effet, seul le fait de mettre à jour automatiquement les données liées nous semble fonctionnellement intéressant, mais est dangereux en terme de gestion des transactions et des conflits d’accès. Il nous semble donc préférable que le programmeur garde la maîtrise de son code, et gère lui-même les affichages et les mises à jour associées à ces contrôles.
Les DataGrids
L'espace de noms System.Windows.Forms propose une classe DataGrid particulièrement bien adaptée à l'affichage des données.
Un DataGrid sert à afficher des données liées sous forme de tableau et permet de les sélectionner, trier et modifier.
Documentation .Net (index) : DataGrid
On utilise le DataGrid pour des liaisons de données complexes, afin d’afficher les champs d'une source de données sous forme de colonnes dans un tableau. Chaque ligne représente un enregistrement de la source de données.
Le DataGrid peut être lié au moment du design en définissant ses propriétés DataSource et DataMember ou au moment de l'exécution en modifiant ces même propriétés ou en appelant la méthode SetDataBinding().
Il est possible de lier un contrôle DataGrid à toute structure de données qui prend en charge l'interface Ilist (ou un dérivé), et sous condition que les objets de cette structure exposent des propriétés publiques.
Alors la grille affichera toutes les propriétés publiques des éléments de la structure de données.
Un tableau représentant une instance de la classe System.Array, une DataTable, un DataSet, ou une DataView sont des exemples de structure adéquate.
Exemple de chargement d’un DataGrid à partir d’un DataSet :
' on crée une connexion, un adapter associé à la commande et un DataSet. On remplit le DataSet grâce au DataAdapteur en créant la table locale Personne
monDataAdapter.Fill(monDataSet, "Personne")
' on remplit le DataGrid avec la table "Personne" du DataSet
' Ceci n’est à faire qu’une fois !!!
dtgListe.DataSource = monDataSet
dtgListe.DataMember = "Personne"
'On peut aussi faire dtgListe.SetDataBinding(monDataSet, "Personne")
' Cela revient au même !!!
Exemple de rafraîchissement d’un DataGrid :
' on vide le Data Set
monDataSet.Clear()
' Attention, passer les bons paramètres si requête paramétrée
da.SelectCommand.Parameters(0).Value = cbnom.Text
' on rafraîchit le Data Set, grâce au Data Adapter
monDataAdapter.Fill(monDataSet, "Personne")
?? EXERCICE 7 et 7bis ;
Afficher tous les comptes dans une grille. (Faire une version par code et une version en
utilisant les assistants.)
11430006540500
?? EXERCICE 8 et 8bis ;
Afficher tous les comptes dans une grille pour un nom saisi. (Faire une version par code et
une version en utilisant les assistants.)
12573002159000
Les ComboBox et les ListBox
Le contrôle ListBox permet d'afficher une liste de choix d'éléments dans laquelle l'utilisateur peut sélectionner en cliquant. Un contrôle ListBox peut fournir des sélections uniques ou multiples suivant la valeur de la propriété SelectionMode.
Un ComboBox affiche un champ d'édition associé à un ListBox, permettant à l'utilisateur de sélectionner dans la liste ou d'entrer un nouveau texte. Par défaut, un ComboBox affiche un champ d'édition avec une liste déroulante masquée. La propriété DropDownStyle détermine le style de la zone de liste déroulante à afficher.
Un CheckedListBox affiche un objet ListBox dans lequel une case à cocher est affichée à gauche de chaque élément.
Les propriétés suivantes permettront de retrouver l’élément sélectionné : SelectedIndex, qui obtient (ou définit) l'index de base zéro de l'élément sélectionné, et SelectedItem qui obtient (ou définit) l’élément sélectionné.
Les collections SelectedIndices et SelectedItems contiennent respectivement les index et éléments lors de sélections multiples.
De plus ces contrôles ont en commun des propriétés qui n’ont de sens que lors du DataBinding :
- DataSource, qui spécifie l’objet source de données,
- DisplayMember, qui spécifie la propriété (nom de la colonne) de la source de données qui doit
être affichée,
- SelectedValue, qui obtient (ou définit) la valeur sélectionnée,
'remplissage combobox
Dim req As String
'Attention!!! aux majuscules dans les noms de colonnes
req = "SELECT nom from Personnes"
Dim com As SqlCommand = New SqlCommand(req, con)
'Ouverture dataadapter
da.SelectCommand = com
da.Fill(ds, "nom")
'remplissage combobox
cbnom.DataSource = ds.Tables("nom")
cbnom.DisplayMember = "nom"
Attention à l'ordre des événements en VB .NET : il ne faut gérer l'événement SelectedIndexChanged sur la liste déroulante que lorsque la fenêtre s'est complètement chargée, sinon on risque d’avoir certaines anomalies. Pour cela, une solution consiste à ajouter, à la fin du chargement de la feuille (load), un handler d’événement SelectedIndexChanged sur la combobox comme suit :
' dans le load de la feuille, terminer l'initialisation, pour accepter
les événements sur la liste déroulante en ajoutant un handler
d'événement sur la liste déroulante
AddHandler cbnNum.SelectedIndexChanged, AddressOf
cbnNum_SelectedIndexChanged
...
' dans l’événement selectedIndexChanged de la liste déroulante,
enlever le handler par défaut (comme suit :)
Private Sub cbnNum_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbnNum.SelectedIndexChanged
?? EXERCICE 9 et 9bis ;
Comme précédemment mais les noms sont proposés dans une liste déroulante.
(Faire une version par code et une version en utilisant les assistants.)
10287009652000
?? EXERCICE 10 ;
A partir de l’exercice précédent, un double clic sur la grille, provoque l’ouverture d’un nouvel écran, qui affiche tous les détails de ce compte et permet des modifications, sauf le numéro de compte.
1143002032000
12573008509000
274320010668000
148590012509500
Conseils :
La grille sera affichée en mode déconnecté via un dataAdapter.
Le numéro de compte sera récupéré au double clic dans une variable.
Le deuxième écran sera ouvert en mode modal
Les détails du compte seront récupérés en mode connecté au load du deuxième écran.
La mise à jour sera effectuée en mode connecté.
A la fermeture du deuxième écran et lors du retour dans le premier, on en profitera pour actualiser la grille.
Les mises a jour via les datasets
Si vous avez lié des éléments d’interface à un DataSet, les données saisies ou modifiées sont répercutées automatiquement dans le DataSet. Par contre la mise à jour de la base de données n’est pas automatique.
La méthode Update du DataAdapter est appelée pour répercuter de telles modifications dans la source de données. La méthode Update, comme la méthode Fill, prend comme arguments une instance d'un DataSet (qui contient les modifications apportées) et un objet DataTable (qui identifie la table où les modifications doivent être extraites).
Lorsque vous appelez la méthode Update, le DataAdapter analyse les modifications apportées. Lorsqu’il trouve une modification dans une ligne (DataRow), il utilise InsertCommand, UpdateCommand ou DeleteCommand pour traiter la modification :
- Vous pouvez spécifier vous-même la syntaxe de la commande (des insert, update ou delete)
au moment du design et, si possible, par l'intermédiaire de l'utilisation de procédures
stockées. Vous devez explicitement définir les commandes avant d'appeler Update. Si
Update est appelé et si la commande appropriée n'existe pas pour une mise à jour
particulière (par exemple pas de DeleteCommand pour les lignes supprimées), une
exception sera levée.
- Dans le cas ou votre DataTable mappe une table de base de données unique, vous pouvez
générer automatiquement les DeleteCommand, InsertCommand et UpdateCommand du
DataAdapter, en utilisant l'objet CommandBuilder.
La méthode Update répercutera vos modifications dans la source de données, cependant d'autres clients peuvent avoir modifié les données au niveau de la source depuis la dernière fois où vous avez rempli le DataSet. Pour actualiser votre DataSet avec les données en cours, utilisez le DataAdapter et remplissez (Fill) à nouveau le DataSet. De nouvelles lignes seront ajoutées à la table et les informations mises à jour seront incorporées dans les lignes existantes.
La méthode Fill détermine si une nouvelle ligne sera ajoutée ou une ligne existante mise à jour en se fondant sur les valeurs de clé primaire des lignes du DataSet et des lignes retournées par SelectCommand. Si une valeur de clé primaire d'une ligne du DataSet correspond à celle d'une ligne des résultats retournés par SelectCommand, la méthode Fill met à jour la ligne existante en y insérant les informations de la ligne retournée par SelectCommand et définit pour le RowState de la ligne existante la valeur Unchanged. Si la valeur de clé primaire d'une ligne retournée par SelectCommand n'a pas de correspondance dans les lignes du DataSet, la méthode Fill ajoute une nouvelle ligne avec un RowState ayant pour valeur Unchanged.
' on actualise le serveur avec les données du Data Set
Try
monDataAdapter.Update(monDataSet, "mesComptes")
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, Me.Text)
End Try
??Attention : l’utilisation du DataSet pour effectuer des modifications (et plus généralement le fait d’effectuer des modifications en mode déconnecté) n’est pas très recommandé. Afin de garantir une bonne gestion des transactions et des conflits d’accès, il est préférable d’effectuer les mises à jour en mode connecté.
Documentation .Net (index) : DataAdapter – méthode Update
Documentation .Net (index) : DataAdapter – Propiétés InsertCommand,
UpdateCommand, DeleteCommand
Les reports
Création d’un Report
La création d’un report s’effectue à l’aide de l’outil intégré CrystalReport.
Pour créer un état, il faut ajouter un nouvel élément dans le projet, de type Etat Crystal Report. On peut ensuite utiliser l’assistant Expert Etat, qui nous guidera tout au long du processus de création de l'état.
Remarque : la Galerie d'états contient un certain nombre d'experts qui peuvent vous aider tout au long de la création de types d'états spécifiques.
8001005016500
262890015557500
32004001651000
262890012763500
Il faut commencer par choisir les données constitutives de l’état. Lorsque l’on est sur cet écran, deux solutions sont possibles : soit on crée complètement l’état en utilisant les assistants (dans ce cas, cliquer sur OLEDB et recréer une connexion, choisir une table et des données à afficher,….), soit on utilise un dataset (basé sur une connexion et une requête) que l’on aura créé par ailleurs (dans le formulaire).
Cette seconde solution parait préférable dans la mesure où le programmeur reste maître de son code. De plus, ceci évite de recréer une connexion différente à chaque état.
Si l’on utilise cette seconde solution, il faut affecter (par code), le Dataset au report, comme suit :
'Après avoir créé un
Private rep As cr
'ouvrir la connection et remplir le data set
Me.da.Fill(Me.Ds)
'transmettre le data set à l'état
rep = New cr
rep.SetDataSource(Me.Ds)
Ensuite on peut passer aux écrans suivants qui vont nous permettre de choisir les colonnes à intégrer dans l’état, de faire de regroupements, d’intégrer des diagrammes, etc….
Exécution du report
Pour exécuter le report, on est obligé d’utiliser le composant CrystalReportViewer, que l’on rajoute à la feuille (il est disponible dans la boîte à outils). Ce composant permet de pré-visualiser l’état et se présente comme suit :
102870013081000
De nombreuses propriétés du CrystalReportViewer permettent de modifier son apparence.
Le CrystalReportViewer est lié au Report soit directement par sa propriété ReportSource, soit par code de la manière suivante :
'lier le crystalviewer crv au Report rep
Me.crv.ReportSource = Me.rep
On peut ensuite imprimer l’état, soit en cliquant sur l’icône d’imprimante du CrystalReportViewer, soit par code de la manière suivante :
'imprimer le Report associé au crystalviewer crv
crv.PrintReport()
Attention : lorsque l’on renseigne la propriété ReportSource du CrystalReportViewer dans l’écran propriétés, le chemin du ReportSource est géré en absolu (et en dur), ce qui pose des problèmes de portabilité.