Site:  Cours VB.net  
6.4 Travailler avec un 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 ? 

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.

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.

 

Imports System.Data

Imports System.Data.OleDb

 

 

 

Il faut créer un objet connexion:

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:

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.

Mycommand.CommandText = "SELECT NOM FROM QUESTIONS"

Ici dans la table QUESTIONS, on extrait le champ NOM

 

Il faut ouvrir la connexion:

MyConnexion.Open()

 

 

Il faut créer un objet DataReader:

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

Do While myReader.Read()

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

Loop

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.

myReader.Close()

MyConnexion.Close()

 

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

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

 

Simple, non!!  (Je rigole!!)

 

Cela donne:

 

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:

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()

 

 

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:

 

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

MyConnexion.Open()

Dim iResultat As Integer = Mycommand.ExecuteScalar()

 

 

Voyons en détails les objets utilisés:

 

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,

..

 

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:

 

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.

 

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

......

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:

Try

    MyConnection.Open()

Catch ex  As OleDbException

    MsgBox(ex.Message)

End Try