Cours VB.NET

Image non disponible


précédentsommairesuivant

XVII-D. ADO:Lire rapidement en lecture seule: le DataReader

Image non disponible

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.

Image non disponible

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.

 
Sélectionnez

Imports System.Data

Imports System.Data.OleDb

Il faut créer un objet connexion:

 
Sélectionnez

Dim MyConnexion As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data source=" & _

"C:\consultation.mdb")

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:

 
Sélectionnez

Dim Mycommand As OleDbCommand = MyConnexion.CreateCommand()

Il faut donner dans la propriété CommandText la requête SQL permettant d'extraire ce que l'on désire.

 
Sélectionnez

Mycommand.CommandText = "SELECT NOM FROM QUESTIONS"

Ici dans la table QUESTIONS, on extrait le champ NOM

Il faut ouvrir la connexion:

 
Sélectionnez

MyConnexion.Open()

Il faut créer un objet DataReader:

 
Sélectionnez

Dim myReader As OleDbDataReader = Mycommand.ExecuteReader()

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

 
Sélectionnez

Do While myReader.Read()

ListBox1.Items.Add(myReader.GetString(0))

Loop

Remarquons que le champ récupéré est typé (ici une string grâce à GetString); 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.

 
Sélectionnez

myReader.Close()

MyConnexion.Close()

On aurait pu libérer la connexion automatiquement dès la lecture terminée en ajoutant un argument:

 
Sélectionnez

Dim myReader As OleDbDataReader = Mycommand.ExecuteReader(CommandBehavior.CloseConnection)

Simple, non!! (Je rigole!!)

Cela donne:

 
Sélectionnez

Imports System

Imports System.Data

Imports System.Data.OleDb

Imports Microsoft.VisualBasic

Public Class Form1

Inherits System.Windows.Forms.Form

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim MyConnexion As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data source=" & _

"C:\consultation.mdb")

Dim Mycommand As OleDbCommand = MyConnexion.CreateCommand()

Mycommand.CommandText = "SELECT NOM FROM QUESTIONS"

MyConnexion.Open()

Dim myReader As OleDbDataReader = Mycommand.ExecuteReader()

Do While myReader.Read()

ListBox1.Items.Add(myReader.GetString(0))

Loop

myReader.Close()

MyConnexion.Close()

End Sub

End Class

Dans le cas d'une base SQLSERVEUR, on aurait les changements suivant:

 
Sélectionnez

Imports System.Data.SqlClient

Dim MyConnexion As SqlConnection = New SqlConnection("Data Source=localhost;" & _
"Integrated Security=SSPI;Initial Catalog=northwind")
Dim Mycommand As SqlCommand = MyConnexion.CreateCommand()

Dim myReader As SqlDataReader = Mycommand.ExecuteReader()

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:

 
Sélectionnez

Mycommand.CommandText = "SELECT COUNT(*) FROM QUESTIONS"

MyConnexion.Open()

Dim iResultat As Integer = Mycommand.ExecuteScalar()

Voyons en détails les objets utilisés:

XVII-D-4. L'objet Connection (détails)

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-5 . L'objet Command (détails)

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 la première colonne de la première ligne.

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-6. L'objet DataReader (détails)

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-7. 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:

 
Sélectionnez

Try

    MyConnection.Open()

Catch ex  As OleDbException

    MsgBox(ex.Message)

End Try

XVII-E. ADO: Travailler sur un groupe de données: le DataSet

Image non disponible

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.

Image non disponible

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.

Image non disponible

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'une 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)
Image non disponible

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:

Image non disponible

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 lignes ont été filtrées (RowFilter), DataView ne comportant qu'une colonne..

Enfin une DataTable ou un DataView peut être affiché dans un contrôle (grid par exemple).

Image non disponible

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 un DataSet, une DataTable ou un DataView à un contrôle DataGrid ou ListBox.. c'est le Data Binding.

XVII-E-2. Utilisation du DataSet, du DataView: en pratique

Ici on utilise uniquement du code.
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.

 
Sélectionnez

Imports System.Data

Imports System.Data.OleDb

Dans la zone Général, Déclarations du module, il faut déclarer les objets Ado:

 
Sélectionnez


'  Déclaration Objet Connexion

Private ObjetConnection As OleDbConnection

' Déclaration Objet Commande

Private ObjetCommand As OleDbCommand

'  Déclaration Objet DataAdapter

Private ObjetDataAdapter As OleDbDataAdapter

' Déclaration Objet DataSet

Private ObjetDataSet As New DataSet() 'Attention au New

'String contenant la 'Requête SQL'

Private strSql As String

' Déclaration Objet DataTable

Private ObjetDataTable As DataTable

' Déclaration Objet DataRow (ligne)

Private ObjetDataRow As DataRow

'Numéro de la ligne en cours

Private RowNumber As Integer    'Numéro de l'enregistrement courant

'Paramêtres de connexion à la DB

Private strConn As String

'Pour recompiler les données modifiées avant de les remettre dans le

'"DataAdapter"

Private ObjetCommandBuilder As OleDbCommandBuilder

'Ouverture

 
Sélectionnez


'Initialisation de la chaîne de paramètres pour la connexion

strConn = "Provider=Microsoft.Jet.OLEDB.4.0;"  _

"Data Source= c:\nom.mdb;"

'Initialisation de la chaîne contenant l'instruction SQL

strSql = "SELECT FICHEPATIENT.* FROM FICHEPATIENT"

'Instanciation d'un Objet Connexion

ObjetConnection = New OleDbConnection()

'Donner à la propriété ConnectionString les paramètres de connexion

ObjetConnection.ConnectionString = strConn

'Ouvrir la connexion

ObjetConnection.Open()

'Instancier un objet Commande

ObjetCommand = New OleDbCommand(strSql)

'Instancier un objet Adapter

ObjetDataAdapter = New OleDbDataAdapter(ObjetCommand)

'initialiser l'objet Command

ObjetCommand.Connection() = ObjetConnection

'Avec l'aide de la propriété Fill du DataAdapter charger le DataSet

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

'Mettre dans un Objet DataTable une table du DataSet

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")

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:

 
Sélectionnez


Dim conn As String = "Provider=Microsoft.Jet.OLEDB.4.0; _
 Data Source=AccessFile.mdb;Persist Security Info=False"

        Dim cmd As String = "Select * from Topics"

        Dim adapter As New OleDbDataAdapter(cmd, conn)

        Dim topics As New Data.DataSet

        adapter.Fill(topics)

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)

 
Sélectionnez


If RowNumber < 0 Then Exit Sub

'Lors de l'ouverture de la BD, s'il n'y a aucun enregistrement

If RowNumber > ObjetDataTable.Rows.Count - 1 Then Exit Sub

'ObjetTable.Rows(Numéro de lignes).Item( Nom de colonne) donne le contenu 
'd'un champ dans une ligne donnée

Me.Nom.Text = ObjetDataTable.Rows(RowNumber).Item("Nom").ToString

Me.Prenom.Text = ObjetDataTable.Rows(RowNumber).Item("Prenom").ToString

'Item peut avoir en paramètre le nom de la colonne ou sont index

Pour se déplacer:

Voir la ligne suivante par exemple:

 
Sélectionnez


RowNumber += 1 incrémente le numéro de la ligne en cours puis on affiche par:

Me.Nom.Text = ObjetDataTable.Rows(RowNumber).Item("Nom").ToString

Me.Prenom.Text = ObjetDataTable.Rows(RowNumber).Item("Prenom").ToString

RowNumber -= 1 pour la précédente.

RowNumber = 0  pour la première.

RowNumber =  ObjetDataTable.Rows.Count - 1  pour la dernière.

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:

 
Sélectionnez


' Extraire l'enregistrement courant

ObjetDataRow = ObjetDataSet.Tables("FICHEPATIENT").Rows(RowNumber)

 

'Modifier les valeurs des champs en  récupérant le contenu des TextBox

ObjetDataRow("Nom") = Me.Nom.Text

ObjetDataRow("Prenom") = Me.Prenom.Text

 

'Pour modifier les valeurs changées dans le DataAdapter

ObjetCommandBuilder = New OleDbCommandBuilder(ObjetDataAdapter)

 

'Mise à jour

ObjetDataAdapter.Update(ObjetDataSet, "FICHEPATIENT")

 

'On vide le DataSet et on le 'recharge' de nouveau.

ObjetDataSet.Clear()

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")

Image non disponible Attention: quand la commande Update est effectuée, si l'enregistrement ne répond pas au spécification de la base ( doublon alors que c'est interdit, pas de valeur pour une clé primaire, Champ ayant la valeur Null alors que c'est interdit..), une exception est levée; si vous ne l'avez pas prévue cela plante!!

Il faut donc mettre la ligne contenant l'Update dans un Try Catch.

Ajouter un enregistrement:

 
Sélectionnez

ObjetDataRow = ObjetDataSet.Tables("FICHEPATIENT").NewRow()

ObjetDataRow("Nom") = Me.Nom.Text

ObjetDataRow("Prenom") = Me.Prenom.Text

ObjetDataSet.Tables("FICHEPATIENT").Rows.Add(ObjetDataRow)

'Pour modifier les valeurs changées dans le DataAdapter

ObjetCommandBuilder = New OleDbCommandBuilder(ObjetDataAdapter)

'Mise à jour

ObjetDataAdapter.Update(ObjetDataSet, "FICHEPATIENT")

'On vide le DataSet et on le 'recharge' de nouveau.

ObjetDataSet.Clear()

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")

il peut y avoir génération d'une exception au niveau de la ligne Update si l'Objet Datarow 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:

 
Sélectionnez

ObjetDataSet.Tables("FICHEPATIENT").Rows(RowNumber).Delete()

ObjetCommandBuilder = New OleDbCommandBuilder(objetDataAdapter)

ObjetDataAdapter.Update(objetDataSet, "FICHEPATIENT")

Fermer

 
Sélectionnez

'Objet connectée

ObjetConnection = Nothing

ObjetCommand = Nothing

ObjetDataAdapter = Nothing

'Objet déconnectée

ObjetDataSet = Nothing

ObjetDataTable = Nothing

ObjetDataRow = Nothing

Trier,Filtrer, rechercher.

Il existe une méthode Select pour les DataTable mais qui retourne des DataRow.

 
Sélectionnez


Dim expression As String = "NOM='LASSERRE'"   'expression à rechercher

Dim sortOrder As String = "Nom DESC"

Dim foundRows() As DataRow     'résultat dans des DataRow

foundRows = ObjetDataTable.Select(expression, sortOrder)

Dim objetDatat1 As New DataTable

For Each r As DataRow In foundRows

objetDatat1.ImportRow(r)

Next

'MsgBox(objetDatat1.Rows.Count)

Dim dv As New DataView(objetDatat1)

DataGrid1.DataSource = dv

Travailler sur une DataTable.

Comment ajouter une ligne (Row)

 
Sélectionnez


Dim LeNewRow As DataRow = ObjetDataTable.NewRow()  'On crée un DataRow

LeNewRow("NOM") = "Smith"  'On remplit la première cellule

ou
LeNewRow(1) = "Smith"

ObjetDataTable.Rows.Add(LeNewRow) 'On ajoute la Row au DataTable

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:

 
Sélectionnez

'On crée un DataView, on y met une table.

Dim dv As DataView

dv.Table =  ObjetDataSet.Tables("FICHEPATIENT")

ou

 
Sélectionnez

Dim dv As New DataView(ObjetDataSet.Tables("FICHEPATIENT")) 'on met une table dans le dataview

ensuite on peut trier le DataView:

 
Sélectionnez

dv.Sort = "Nom DESC"  'on trie  sur le champ Nom en ordre décroissant (ASC pour un tri croissant).

On peut filtrer le DataView:

 
Sélectionnez

dv.RowFilter = " PreNom = 'Philippe'"  'bien respecter les  '. et les majuscules/minuscules.

Le DataView ne contient plus que les rows dont la col ="Philippe". On peut afficher dans une grid.

 
Sélectionnez

DataGrid1.DataSource = objetDataView

On peut rechercher dans le DataView avec Find:

 
Sélectionnez

    Dim dv As DataView = New DataView(Mytable)
    dv.Sort = "CustomerID"

    ' Cherche le customer named "DUPONT" dans la première colonne
    Dim i As Integer = dv.Find("DUPONT")
    Console.WriteLine(dv(i))'Affiche sur la console

Il existe 'FindRows' qui retourne des DataRow.

Ensuite on peut lier le DataView à une Grid.

XVII-E-3. Remplir un DataGrid ou une ListBox avec un DataSet

Une fois que le dataSet existe, en UNE ligne de 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:

 
Sélectionnez

Dim matable As New DataTable

matable = ObjetDataSet.Tables("FICHEPATIENT")

DataGrid1.DataSource = matable

Remplir une Listbox ligne par ligne:

 
Sélectionnez

Dim matable As New DataTable

matable = ObjetDataSet.Tables("FICHEPATIENT")

Dim Ligne As DataRow()

For Each Ligne In Matable.Rows

          List1.Items.Add(ligne.Item(" Nom "))

Next

XVII-E-4. Étudions en détail un DataSet

Un DataSet est un cache de données en mémoire. 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.

 
Sélectionnez

			Private myDataSet As DataSet


' Créer une nouvelle DataTable.
Dim myDataTable As DataTable = new DataTable("ParentTable")
' Declaration de variables DataColumn et DataRow objects.
Dim myDataColumn As DataColumn
Dim myDataRow As DataRow

' Créer un nouveau DataColumn, lui donner un DataType, un nom, divers valeurs pour ses propriétés  
'et l'ajouter à la DataTable.
myDataColumn = New DataColumn()
myDataColumn.DataType = System.Type.GetType("System.Int32")    'Type de la colonne
myDataColumn.ColumnName = "id"                                 'Nom de la colonne
myDataColumn.ReadOnly = True                                   'Colonne ReadOnly
myDataColumn.Unique = True                                     'Evite les doublons 
myDataTable.Columns.Add(myDataColumn)

' Créer une seconde column.
myDataColumn = New DataColumn()
myDataColumn.DataType = System.Type.GetType("System.String")
myDataColumn.ColumnName = "ParentItem"
myDataColumn.AutoIncrement = False
myDataColumn.Caption = "ParentItem"
myDataColumn.ReadOnly = False
myDataColumn.Unique = False
myDataTable.Columns.Add(myDataColumn)

'La colonne id doit être une clé primaire.
Dim PrimaryKeyColumns(0) As DataColumn
PrimaryKeyColumns(0)= myDataTable.Columns("id")
myDataTable.PrimaryKey = PrimaryKeyColumns
 

'la colonne peut être une colonne auto incrémentée: (la valeur du champ "CustomerID" démarre à 100 , 
's'incrémente de 2 automatiquement à chaque création de DataRow.

Dim MyDataColumn2 As DataColumn = MyDataTable.Columns.Add("CustomerID", typeof(Int32))
MyDataColumn2.AutoIncrement = true
MyDataColumn2.AutoIncrementSeed = 100
MyDataColumn2.AutoIncrementStep = 2

Il est bon de la mettre en Readonly

 
Sélectionnez


' Créer un objet DataSet
myDataSet = New DataSet()
' Ajouter la Table au DataSet.
myDataSet.Tables.Add(myDataTable)

' Créer 3 DataRow objects (3 lignes)  et les ajouter à la DatTable
Dim i As Integer
For i = 0 to 2
myDataRow = myDataTable.NewRow()
myDataRow("id") = i
myDataRow("ParentItem") = "ParentItem " + i.ToString()
myDataTable.Rows.Add(myDataRow)
Next i
End Sub

 

'parcourir dans la table 'ParentTable' toutes les lignes et lire le premier élément (1ère colonne)


For compteur=0 To myDataSet.Tables("ParentTable").Rows.Count -1

    Element= myDataSet.Tables("ParentTable").Rows.(compteur).Item(0)

Next compteur

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"

Image non disponible

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ée 'BaseNom', j'ai une table 'NomPatient' avec plusieurs colonnes, je veux afficher la colonne des noms dans une listBox:

Image non disponible

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.

Image non disponible

Bien sur il faut importer des espaces de nom:

 
Sélectionnez


Imports System

Imports System.Data

Imports System.Data.OleDb

Dans la zone déclaration de la fenêtre:

 
Sélectionnez

'Déclarer la connexion

Private ObjetConnection As OleDbConnection

' Déclaration l'Objet Commande

Private ObjetCommand As OleDbCommand

' Déclaration Objet DataAdapter

Private ObjetDataAdapter As OleDbDataAdapter

' Déclaration Objet DataSet

Private ObjetDataSet As New DataSet

'String contenant la 'Requête SQL'

Private strSql As String

' Déclaration Objet DataTable

Private ObjetDataTable As DataTable

'Paramêtres de connexion à la DB

Private strConn As String

Dans une routine Button1_Click créer les divers objets et remplir la listbox.

 
Sélectionnez

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

'Initialisation de la chaîne de paramètres pour la connexion

strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source= c:\Basenom.mdb;"

'Initialisation de la chaîne contenant l'instruction SQL

strSql = "SELECT FICHEPATIENT.* FROM FICHEPATIENT"

'Instanciation d'un Objet Connexion

ObjetConnection = New OleDbConnection

'Donner à la propriété ConnectionString les paramètres de connexion

ObjetConnection.ConnectionString = strConn

'Ouvrir la connexion

ObjetConnection.Open()

'Instancier un objet Commande

ObjetCommand = New OleDbCommand(strSql)

'Instancier un objet Adapter

ObjetDataAdapter = New OleDbDataAdapter(ObjetCommand)

'initialiser l'objet Command

ObjetCommand.Connection() = ObjetConnection

'Avec l'aide de la propriété Fill du DataAdapter charger le DataSet

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

'Mettre dans un Objet DataTable une table du DataSet

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")

 

'Indiquer au ListBox d'afficher la table "fichepatient" (indiquer la source)

ListBox1.DataSource = ObjetDataSet.Tables("FICHEPATIENT")

'Indiquer quelle colonne afficher

ListBox1.DisplayMember = "NOM"

End Sub

 

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; 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):

 
Sélectionnez

ListBox1.DataSource = ObjetDataSet.Tables("FICHEPATIENT")

ListBox1.DisplayMember = "NOM"

ListBox1.ValueMember = "NUMINT"

ValueMember ne fonctionne pas bien, et ListBox1.SelectedValue retourne un objet de type DataRowView impossible à utiliser.

Il faut donc renseigner le DataSource en dernier.

 
Sélectionnez

ListBox1.DisplayMember = "NOM"

ListBox1.ValueMember = "NUMINT"

ListBox1.DataSource = ObjetDataSet.Tables("FICHEPATIENT")

'Dans ce cas ListBox1.SelectedValue contient bien un Int32 correspondant au 'NutInt' selectionné.

'Ensuite on peut récupérer sans problème NumInt (et l'afficher par exemple dans une TextBox)

Private Sub ListBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) 
_Handles ListBox1.SelectedIndexChanged

Dim o As New Object

If ListBox1.SelectedIndex <> -1 Then

TextBox1.Text = CType(ListBox1.SelectedValue, String)

End If

End Sub

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:

 
Sélectionnez

' Déclaration Objet Connection

Private ObjetConnection As OleDbConnection

' Déclaration Objet Commande

Private ObjetCommand As OleDbCommand

' Déclaration Objet DataAdapter

Private ObjetDataAdapter As OleDbDataAdapter

' Déclaration Objet DataSet

Private ObjetDataSet As New DataSet

' Déclaration Objet DataTable

Private ObjetDataTable As New DataTable

'String contenant la 'Requête SQL'

Private strSql As String

'Paramêtres de connexion à la DB

Private strConn As String

' Déclaration d'un  OleDbCommandBuilder

Private ObjetCB As OleDbCommandBuilder

Le bouton ButtonAfficheGrid remplie le DataGrid avec nom.mdb table 'FICHEPATIENT'

 
Sélectionnez


Private Sub ButtonAfficheGrid_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 
_Handles ButtonAfficheGrid.Click

'Initialisation de la chaîne de paramètres pour la connexion

strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source= c:\nom.mdb;"

'Initialisation de la chaîne contenant l'instruction SQL

strSql = "SELECT FICHEPATIENT.* FROM FICHEPATIENT"

'Instanciation d'un Objet Connexion

ObjetConnection = New OleDbConnection

'Donner à la propriété ConnectionString les paramètres de connexion

ObjetConnection.ConnectionString = strConn

'Ouvrir la connexion

ObjetConnection.Open()

'Instancier un objet Commande

ObjetCommand = New OleDbCommand(strSql)

'Instancier un objet Adapter

ObjetDataAdapter = New OleDbDataAdapter(ObjetCommand)

'initialiser l'objet Command

ObjetCommand.Connection() = ObjetConnection

'initialiser l'objet OleCBComandBuilder (sinon pas d'update)

ObjetCB = New OleDbCommandBuilder(ObjetDataAdapter)

'Avec l'aide de la propriété Fill du DataAdapter charger le DataSet

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

'Créer une datatable à partir du dataset

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")

'Mettre dans le DataGrid une table  DataTable

DataGrid1.DataSource= ObjetDataTable

End Sub

Le bouton ButtonMiseA jour met à jour nom.mdb si on a fait une modification dans le DataGrid.

 
Sélectionnez

Private Sub ButtonMiseAJour_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 
_Handles ButtonMiseAJour.Click

    'Mettre à jour

    ObjetDataAdapter.Update(ObjetDataSet, "FICHEPATIENT")

End Sub
Image non disponible

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:

 
Sélectionnez

DataGrid1.DataSource = ObjetDataSet

DataGrid1.DataMember = "FICHEPATIENT"

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!!

Image non disponible

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'

Image non disponible

Ici la source de données est une base de données:

Image non disponible

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".

Image non disponible

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.

Image non disponible

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.

Image non disponible

Ensuite il faut choisir dans la base les objets qui seront chargés dans le dataset.

C'est habituellement les Tables. Cocher 'Tables'.

Image non disponible

Cliquer sur "Terminer".

Pour voir les sources de données, cliquer sur le menu 'Données' 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.

Image non disponible

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.

 
Sélectionnez

Private Sub Form1_Load

'Création d'un TableAdapter

Dim FPTableAdapter = New NOMDataSetTableAdapters.FICHEPATIENTTableAdapter

'Extraction des données et chargement du DataSet

FPTableAdapter.Fill(NOMDataSet.FICHEPATIENT)

End Sub

Il faut ensuiteajouter une grid puis faire le lien DataSet-Grid.

Dans les propriétés de DataGrid il faut enseigner DataSource et DataMember.

Image non disponible

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.

 
Sélectionnez

Private Sub Enregistrer_Click

Dim PatTableAdapter = New NOMDataSetTableAdapters.FICHEPATIENTTableAdapter

NOMDataSetBindingSource.EndEdit()

'Vérifiez que des modifications ont eu lieu

If NOMDataSet.HasChanges Then

    'Appliquer les changements dans la base de données

    PatTableAdapter.Update(NOMDataSet.FICHEPATIENT)

End If

End Sub

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'

Image non disponible

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)
Image non disponible

On voit bien en dessous les 4 composants qui ont été ajoutés.

C'est terminé!!

Il suffit de lancer le programme, et on 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:

Image non disponible

XVII-F-3-d. Binding et TextBox

Pour générer, non pas 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:

Image non disponible

précédentsommairesuivant

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © . Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.