Cours VB.NET
Date de mise à jour : 02/08/2009
XVII-D. Lire rapidement en lecture seule : le DataReader
XVII-D-1. Généralités
XVII-D-2. Exemple de DataReader avec une base Access
XVII-D-3. Comment compter ?
XVII-D-3-a. L'objet Connection
XVII-D-3-b. L'objet Command
XVII-D-3-c. L'objet DataReader
XVII-D-3-d. Exceptions
XVII-E. Travailler sur un groupe de données : le DataSet
XVII-E-1. Généralités
XVII-E-2. Utilisation du DataSet, du DataView : en pratique
XVII-E-3. Remplir un DataGrid ou une ListBox avec un DataSet
XVII-E-4. Étudions en détail un DataSet
XVII-F. Liaison DataGrid, ListBox et base de données : le "DataBinding"
XVII-F-1. Remplir une ListBox avec une colonne d'une table d'une BD
XVII-F-2. Remplir un DataGrid avec une base de données via un DataSet
XVII-F-3. Remplir un contrôle avec une source de données avec le moins de code possible(VB 2005 2008).
XVII-F-3-a. Création de la source de données
XVII-F-3-b. Liaison source de données-Grid avec du code.
XVII-F-3-c. Génération automatique de l'interface utilisateur
XVII-F-3-d. Binding et TextBox
XVII-D. Lire rapidement en lecture seule : le DataReader
Comment lire rapidement des enregistrements? Avec un DataReader.
Comment compter les enregistrements? Avec ExecuteScalar
Etudions en détail les objets Connexion, Command, DataReader.
Et s'il y a une erreur ?
XVII-D-1. Généralités
Un objet DataReader fournit des données en lecture seule en un temps record. La seule possibilité est de se déplacer en avant.
En contrepartie de sa rapidité il monopolise la connexion.
Il faut créer un objet Connexion puis un objet Command, ensuite on exécute la propriété ExecuteReader pour créer l'objet DataReader; enfin on parcourt les enregistrements avec la méthode Read.
XVII-D-2. Exemple de DataReader avec une base Access
Il existe une base Access nommée 'consultation.mdb', elle contient une table 'QUESTIONS', dans cette table existe un champ 'NOM', je veux récupérer tous les noms et les afficher rapidement dans une ListBox.
Il faut importer les NameSpaces nécessaires.
|
Il faut créer un objet connexion:
|
Il faut donner les paramètres Provider= et Data source=
Dans le cas d'une base Access le provider (le moteur à utiliser est le moteur OLEDB Jet 4.
Il faut créer un objet Command:
|
Il faut donner dans la propriété CommandText la requête SQL permettant d'extraire ce que l'on désire.
|
Ici dans la table QUESTIONS, on extrait le champ NOM
Il faut ouvrir la connexion:
|
Il faut créer un objet DataReader:
|
On crée une boucle permettant de lire les enregistrements les uns après les autres, on récupère le champ (0) qui est une String, on la met dans la ListBox
|
Remarquons que le champ récupéré est récupéré typé (ici une string grâce à GeString); il y a d'autres types: GetDateTime, GetDouble, GetGuid, GetInt32, GetBoolean, GetChar, GetFloat, GetByte, GetDecimal etc..; il est possible de récupérer sans typage: on aurait écrit myReader(0) ou utiliser GetValue (on récupère un objet).
Read avance la lecture des données à l'enregistrement suivant , il retourne True s'il y a encore des enregistrements et False quand il est en fin de fichier; cela est utilisé pour sortir de la boucle Do Loop.
On ferme pour ne pas monopoliser.
|
On aurait pu libérer la connexion automatiquement dès la lecture terminée en ajoutant un argument:
|
Simple, non!! (Je rigole!!)
Cela donne:
|
Dans le cas d'une base SQLSERVEUR, on aurait les changements suivant:
|
XVII-D-3. Comment compter ?
Avec ExecuteScalar de l'objet Command on peut récupérer les résultats d'une requête Sql qui contient une instruction COUNT (comptage) AVG (moyenne) MIN (valeur minimum) MAX (valeur maximum) SUM (somme)
Exemple: compter le nombre de questions:
|
Voyons en détails les objets utilisés:
XVII-D-3-a. L'objet Connection
Il permet de définir une connexion.
Il faut donner les paramètres 'Provider='indiquant le moteur de BD et 'Data source=' indiquant le chemin et le nom de la BD. Il peut être nécessaire de donner aussi 'Password=' le mot de passe , 'User ID=' Admin pour l'administrateur par exemple.
Il faut mettre ces paramètres avec le constructeur, ou dans la propriété ConnectionString.
Dans le cas d'une base Access le provider (le moteur à utiliser) est le moteur OLEDB Jet 4.
Il y a d'autres propriétés:
State état de la connexion (Open, Close, Connecting, Executing, Fetching, Broken)
Open, Close
ConnectionTimeOut,
BeginTransaction,
..
XVII-D-3-b. L'objet Command
Pour chaque provider il y a un objet Command spécifique:
SqlCommand, OleDbCommand, mais tous les objets 'Command' on la même interface, les mêmes membres.
CommandType indique comment doit être traité la commande CommandText:
- Text ; par défaut (exécution direct des instructions SQL contenues dans CommandText)
- StoredProcedure: exécution de procédure stockée dont le nom est dans CommandText.
- Tabledirect?
Command permet de définir la commande à exécuter: SELECT UPDATE, INSERT, DELETE. en utilisant le membre CommandText
(Seul SELECT retourne des données)
CommandTimeOut indique la durée en secondes avant qu'une requête qui plante soit abandonnée.
ExecuteReader exécute le code SQL de CommandText et retourne un DataReader.
ExecuteScalar fait de même mais retourne les champs de la premier colonne pour une fonction Count ou Sum.
ExecuteNoQuery exécute le code SQL de CommandText (généralement une mise à jour par UPDATE, INSERT, DELETE ou un ajout de table) sans retourner de données.
XVII-D-3-c. L'objet DataReader
Pour chaque provider il y a un objet 'DataReader' spécifique:
SqlDatReader, OleDbDataReader
On a vu le membre Read qui avance la lecture des données à l'enregistrement suivant , il retourne True s'il y a encore des enregistrements et False quand il est en fin de fichier.
On a vu GetDateTime, GetDouble, GetGuid, GetInt32, GetBoolean, GetChar, GetFloat, GetByte, GetDecimal permettant de récupérer les valeurs typées des champs.
Il a bien d'autres propriétés:
GetName retourne le nom du champ (numéro du champ en paramètre)
GetOrdinal fait l'inverse: retourne le numéro du champ (nom en paramètre)
FieldCount retourne le nombre de colonne.
GetDataTypeName retourne le nom du type de donnés.
IsDBNull retourne True si le champ est vide
......
XVII-D-3-d. Exceptions
Chaque SGDB a des erreurs spécifiques. Pour les détecter il faut utiliser les types d'erreur spécifiques: SqlException et OleDbException par exemple:
Exemple d'interception d'erreur:
|
XVII-E. Travailler sur un groupe de données : le DataSet
Comment travailler (lire écrire, modifier, trier..) sur des enregistrements d'une base de données ?
Avec un DataSet.
XVII-E-1. Généralités
Le DataSet est une représentation en mémoire des données. On charge le DataSet à partir de la base de données. Une fois chargé on peut travailler en mode déconnecté. Pour effectuer une modification, on modifie le DataSet puis on met à jour la base de donnée à partir du DataSet.
Pour remplir un DataSet il faut une Connexion puis un DataAdapter.
Il faut créer un objet Connexion puis un objet DataAdapter qui par sa propriété Fill charge le DataSet.
Les données sont extraites à l'aide de requête SQL sur l'objet Command, et on utilise un CommandBluider pour mettre à jour la base de donnée à partir du DataSet.
Le DataSet est organisé comme une base de données en mémoire, il possède:
- Une propriété Tables qui contient des DataTable (Comme les tables d'un BD)
- Chaque DataTable contient une propriété Columns qui contient les DataColomn (les colonnes ou champs des BD) et une propriété Rows qui contient des DataRow (Les lignes ou enregistrements des BD)
DataColumn contient des informations sur le type du champ.
DataRow permet d'accéder aux données.
Un DataSet possède aussi la propriété Constraints qui contient les Constraint (Clé primaire ou clé étrangère), et la propriété Relations qui contient les DataRelations(Relation entre les tables).
On peut créer des DataTable 'autonomes' et y mettre une table provenant d'un dataSet:
On peut créer des DataView : Vue, représentation d'une table. A partir d'une table, on peut créer plusieurs DataView avec des représentations différentes: DataView trié, DataView donc les ligne ont été filtrées (RowFilter)
Enfin une DataTable ou un DataView peut être affichés dans un contrôle (grid par exemple).
En conclusion: on connecte la base de donnée au DataSet par l'intermédiaire de Connexion et DataAdapter. Ensuite, il y a 2 manières de 'travailler':
- A - On utilise les membres du DataSet pour lire ou modifier les données.
- B - On lie le DataSet, une DataTable ou un DataView à un contrôle DataGrid ou ListBox..Et tout s
XVII-E-2. Utilisation du DataSet, du DataView : en pratique
Soit une base de données Access nommée 'Nom.mdb', elle contient une table 'FichePatient' qui contient les champs (ou colonnes) 'Nom', 'Prenom'.
Je vais me connecter à cette base, extraire les enregistrements de la table 'FichePatient' et les mettre dans un DataSet. Chaque ligne du DataSet contient un patient. Je travaillerais sur ces lignes.
En tête du module, il faut importer l'espace de nom permettant d'utiliser les DataSet et OleDB.
|
Dans la zone Général, Déclarations du module, il faut déclarer les objets Ado:
|
'Ouverture
|
Ici le code est simplifié, mais dans la réalité, il est indispensable d'user de Try Catch pour capter les exceptions surtout pour ObjetConnection.Open() et pour l'update.
Les extraits (snippets) de VB 2005, donne un exemple de code plus condensé pour ouvrir un DataSet:
|
Voir un enregistrement:
Routine affichant un enregistrement:
Une TextBox nommée 'Nom' et une TextBox 'Prenom' afficheront les noms et prénom des patients.
On rappelle que RowNumber est une variable contenant le numéro de la ligne en cours ( allant de 0 à Rows.Count-1)
|
Pour se déplacer:
Voir la ligne suivante par exemple:
|
On remarque qu' il n'y a pas d'enregistrement courant,pas de pointeur sur un enregistrement, c'est vous même qui gérez RowNumber une simple variable qui contient le numéro de l'enregistrement (l'index du DataRow) sur lequel vous travaillez.
Modifier un enregistrement:
|
Il faut donc mettre la ligne contenant l'Update dans un Try Catch.
Ajouter un enregistrement:
|
il peut y avoir génération d'une exception au niveau de la ligne Update si l'ObjetDatarow présente un 'défaut', par exemple si un champ de l'ObjetDatarow a une valeur null (il n'a pas été renseigné) alors qu'il sert l'index.
Effacer l'enregistrement en cours:
|
Fermer
|
Trier,Filtrer, rechercher.
Il existe une méthode Select pour les DataTable mais qui retourne des DataRow.
|
Travailler sur une DataTable.
Comment ajouter une ligne (Row)
|
Utiliser un DataView.
Mais on peut aussi passer la table dans un DataView et utiliser Find Sort RowFilter sur le DataView.
Le DataView est un objet qui ressemble à une table mais qui correspond à une représentation et permet les tris ou l'utilisation d'un filtre:
|
ou
|
ensuite on peut trier le DataView:
|
On peut filtrer le DataView:
|
Le DataView ne contient plus que les rows dont la col ="Philippe". On peut afficher dans une grid.
|
On peut rechercher dans le DataView avec Find:
|
FindRows lui retourne des DataRow
Ensuite on peut lier le DataView à une Grid.
Dim somme As Objet= ObjetDataTable.Compute("Sum (PRIX)", "Categorie=5")
On peut aussi utiliser Count() et dans le second paramètre (le filtre)) utiliser des And.
XVII-E-3. Remplir un DataGrid ou une ListBox avec un DataSet
Une fois que le dataSet existe, en UNE lignede code, on peut l'afficher dans un DataGrid.(Grille avec des lignes et des colonnes comme un tableur)
DataGrid1.SetDataBinding(ObjetDataSet, "FICHEPATIENT") en VB2003 on associe le dataset à la grid
On peut aussi passer par l'intermédiaire d'une DataTable en VB 2003 et VB 2005:
|
Remplir une Listbox ligne par ligne
|
XVII-E-4. Étudions en détail un DataSet
Un DataSet est un groupe de données. On a vu qu'on pouvait le remplir avec une base de données mais on peut imaginer le créer de toute pièce et le remplir en créant des tables, des colonnes, des données.
Dans un DataSet on peut donc ajouter des tables, dans les tables des colonnes, des enregistrements.
L'exemple suivant crée un objet DataTable, qui sera ajouté au DataSet.
|
Il est bon de la mettre en readonly
|
Travailler avec la Base MySQL
Pour travailler sur une base MySQL lisez le très bon didacticiel MySQLDotNet (sur developpez.com bien sur)
XVII-F. Liaison DataGrid, ListBox et base de données : le "DataBinding"
A - Comment remplir des listBox avec des tables venant de base de données?
B - Comment remplir des DataGrid avec des tables venant de base de données?
C - Comment avec quelques click et sans une ligne de code, créer une application permettant d'afficher le contenu d'une base de données? (en VB 2005)
Cette liaison de données entre une source de données et un contrôle se nomme'DATABINDING'
XVII-F-1. Remplir une ListBox avec une colonne d'une table d'une BD
Ici, on va tout faire avec du code.
Exemple:
Dans une base de données Accès nommé 'BaseNom', j'ai une table 'NomPatient' avec plusieurs colonnes, je veux afficher la colonne des noms dans une listBox:
On peut utiliser un 'DataReader'
Voir le chapitre sur le DataReader
C'est de la 'lecture seule' très rapide.
On peut utiliser un 'DataSet', créer un 'DataTable' et la lier au contrôle.
Le DataSet est une représentation en mémoire des données; Une fois chargé on peut travailler en mode déconnecté.
Pour le remplir il faut un DataAdapter.
Bien sur il faut importer des espaces de nom:
|
Dans la zone déclaration de la fenêtre:
|
Dans une routine Button1_Click créer les divers objets et remplir la listbox.
|
Voilà, cela affiche la liste des noms.
Bien respecter les minuscules et majuscules dans les noms de tables et de champs+++
Récupérer la valeur d'un autre champ
On a vu que dans la table, chaque enregistrement avait un champ 'Nom' mais aussi un champ 'NumInt' (numéro interne)
Dans les programmes, on a souvent besoin de récupérer le numéro interne (un ID) quand l'utilisateur clique sur un des noms; le numéro interne servira a travailler sur ce patient.
Exemple: comment récupérer le numéro interne 3 quand l'utilisateur clique sur 'Thomas'?
Il faut indiquer à la ListBox que la Value de chaque ligne est 'NumInt' en utilisant la propriété ListBox1.ValueMember.
Quand l'utilisateur clique sur une ligne de la ListBox, cela déclenche l'évènement ListBox1_SelectedIndexChanged, là on récupère la valeur de NumInt correspondant; elle se trouve dans ListBox1.SelectedValue. (C'est un Int32)
Attention:
Les exemples de Microsoft ne fonctionnent pas!! car, on n'explique nulle part l'importance de l'ordre des lignes remplissant la ListBox.
C'est DataSource qui semble déclencher le chargement de la ListBox avec la prise en compte de DisplayMember et ValueMember.
Si on fait comme Microsoft (renseigner ListBox1.DataSource en premier):
|
ValueMember ne fonctionne pas bien, et ListBox1.SelectedValue retourne un objet de type DataRowView impossible à utiliser.
Il faut donc renseigner le DataSource en dernier.
|
XVII-F-2. Remplir un DataGrid avec une base de données via un DataSet
Avec mise à jour de la base de donnée, si on fait une modification dans le Datagrid. Oui ça marche.(Depuis que j'ai ajouté le CommandBluider)
Ici, on va tout faire avec du code.
Il faut créer une 'Connection', un DataAdapter et un DataSet, puis en UNE ligne de code, on peut l'afficher dans un DataGrid.(Grille avec des lignes et des colonnes comme un tableur), ne pas oublier le CommandBuilder sinon Update ne marche pas.
Dans la zone de déclaration:
|
Le bouton ButtonAfficheGrid remplie le DataGrid avec nom.mdb table 'FICHEPATIENT'
|
Le bouton ButtonMiseA jour met à jour nom.mdb si on a fait une modification dans le DataGrid.
|
Les lignes, colonnes, nom des champs, ascenseurs... sont crées automatiquement avec la table "FICHEPATIENT"!! Génial.
On peut cliquer dans une cellule, la modifier..rajouter ou enlever des lignes.
On peut aussi remplir le Datagrid avec:
|
En mode Design, on peut modifier l'aspect du DataGrid dans la fenêtre de propriété ou en utilisant la mise en forme automatique (lien en bas de la fenêtre de propriétés.)en VB 2003!!
XVII-F-3. Remplir un contrôle avec une source de données avec le moins de code possible(VB 2005 2008).
Ici, on va créer une source de données (sans code, avec l'IDE).puis on fera un binding sur le contrôle d'abord avec du code puis sans code.
On a une base de données Access (Nom.MDB), on veut afficher le contenu d'une des tables (la table 'FICHEPATIENT') dans une grille.
- Il faut créer une source de données: la BD Nom.MDB.
- Il faut créer l'interface utilisateur.
- Il faut créer les liens entre cette interface et une table de la BD.
XVII-F-3-a. Création de la source de données
On veut créer sans code une source de données:
Menu 'Données'=> 'Ajouter une nouvelle source de données'
Ici la source de données est une base de données:
On clique sur 'Base de données' puis bouton 'Suivant'.
Ensuite il faut faire le choix de la connexion (Cela correspond au choix d'une base de données existante).
Cliquer sur 'Nouvelle connexion'. Une nouvelle fenêtre nommée 'Ajouter une connexion' s'ouvre:
Indiquer le type de source de données (ici Microsoft Access (OLEDB), puis le nom de la base de données; enfin cliquer sur "Ok".
On retrouve le nom de la bd dans la zone connexion, cliquer sur "Suivant".
Ensuite VB vous demande s'il faut copier la BD dans le projet: Si oui la BD sera copiée dans le répertoire de travail quand vous installerez votre application. A vous de voir.
Ensuite VB vous propose d'enregistrer les chaînes de connexion (nom de la base...) dans le fichier de configuration afin qu'elles soient stockées et lues lors de l'utilisation ultérieure. (Automatiquement bien sur) A vous de voir.
Ensuite il faut choisir dans la base les objets qui seront chargés dans le dataset.
C'est habituellement les Tables. Cocher 'Tables'.
Cliquer sur "Terminer".
Pour voir les sources de données, cliquer sur le menu 'Dones' puis 'Voir les sources de données'.
On voit bien dans notre exemple 'NOMDataSet' le DataSet de la source de données qui contient FICHEPATIENT.
On voit bien dans notre exemple 'NOMDataSet' le DataSet de la source de données qui contient FICHEPATIENT.
XVII-F-3-b. Liaison source de données-Grid avec du code.
Maintenant qu'on a la source de données, on va créer un DataAdapter et une Grid qu'on va remplir grâce à sa propriété 'DataSource'.
On utilisera la méthode Fill du TableAdapter.
|
Il faut ensuiteajouter une grid puis faire le lien DataSet-Grid.
Dans les propriétés de DataGrid il faut enseigner DataSource et DataMember.
On exécute, la grille se remplit avec les données.
Comment enregistrer les modifications de la grid effectuées par l'utilisateur dans la base de données:
Pour que les modifications de la grille soient répercutées dans le DataSet, il faut enregistrer le DataSet dans la base grâce au TableAdapter et à sa méthode Update.
|
XVII-F-3-c. Génération automatique de l'interface utilisateur
Plutôt que de faire le binding 'à la main' et taper du code comme ci-dessus, on peut tout faire faire par VB.
Visual Studio dispose d'une fenêtre 'Sources de données' depuis laquelle vous pouvez faire glisser des éléments jusqu'à un formulaire pour créer automatiquement des contrôles liés aux données qui affichent des données.
Afficher les sources de données:
Menu 'Données' puis 'Afficher les sources de données'
Il apparaît à droite la fenêtre 'Sources de données'
Dérouler 'NomDataSet'(c'est le nom donné par VB à la connexion) et cliquer sur 'FICHEPATIENT' (c'est le nom d'une table de la BD).
Enfin faire un drag and drop à partir de FICHEPATIENT et déposer le sur la form de gauche (qui est vide au départ)
Miracle: il apparaît automatiquement:
- un datagrid.
- une barre de navigation (tout est généré automatiquement: les bitmap des boutons dans les ressources Setting...)
- Un DataSet, un TableAdapter
- Un composant BindingSource.(Il fait le lien entre l'interface et la source de données)
- Un composant BindingNavigator.(Il gère la barre de navigation)
On voit bien en dessous les 4 composants qui ont été ajoutés.
C'est terminé!!
Il suffit de lancer le programme, et on se voit la bd dans la grille, on se ballade dedans avec le curseur ou la barre de navigation, on peut ajouter, effacer une ligne, enregistrer les modifications:
XVII-F-3-d. Binding et TextBox
Pour générer, non par une grid mais des zones de saisie textbox pour chaque champ, avant de faire le drag and drop, dérouler la liste contre la Table dans les sources de données et cliquer sur 'Détails'.
Il y a un exemple dans la section sur les classes, Programme à 3 couches qui donne ceci:
Aucun commentaire:
Enregistrer un commentaire