VII. Rappels ADO▲
VII-A. L'objet Connection▲
Je ne vais pas me lancer ici dans une longue description de l'objet Connection. Je vais donc juste faire quelques rappels directement utilisés dans cet article.
VII-A-1. La propriété CursorLocation▲
Définit ou renvoie la position de la bibliothèque de curseur à utiliser. Peut prendre les valeurs adUseClient ou adUseServer. La définition de cette propriété au niveau de la connexion permet de ne pas la re déclarer au niveau d'un recordset.
VII-A-2. La propriété IsolationLevel▲
Cette propriété permet de définir le niveau d'isolation qu'auront les transactions faites par la connexion. Ceci permet de garantir le respect de la gestion des transactions. Elle peut prendre les valeurs :
Constante |
Valeur |
Description |
---|---|---|
adXactUnspecified |
-1 |
Le fournisseur utilise un niveau d'isolation différent de celui qui est spécifié, mais ce niveau ne peut pas être déterminé. |
adXactChaos |
16 |
Valeur utilisée par défaut. Vous ne pouvez pas écraser les changements en attente des transactions dont le niveau d'isolation est supérieur. |
adXactBrowse |
256 |
À partir d'une transaction, vous pouvez voir les modifications des autres transactions non encore engagées. |
adXactReadUncommitted |
256 |
Identique à adXactBrowse |
adXactCursorStability |
4096 |
Valeur utilisée par défaut. À partir d'une transaction, vous pouvez afficher les modifications d'autres transactions uniquement lorsqu'elles ont été engagées. |
adXactReadCommitted |
4096 |
Identique à adXactCursorStability. |
adXactRepeatableRead |
65536 |
À partir d'une transaction, vous ne pouvez pas voir les modifications effectuées dans d'autres transactions, mais cette nouvelle requête peut renvoyer de nouveaux jeux d'enregistrements. |
adXactIsolated |
1048576 |
Des transactions sont conduites en isolation d'autres transactions. |
adXactSerializable |
1048576 |
Identique à adXactIsolated. |
Le niveau d'isolation à utiliser dépend de votre application. La valeur la plus stricte (sure) est adXactIsolated
VII-A-3. La propriété Mode▲
Cette propriété permet de gérer en partie l'accès concurrentiel dans les bases de données. Comme cette propriété porte sur la connexion, elle s'applique à la source de données. Elle peut prendre les valeurs :
Constante |
Valeur |
Description |
---|---|---|
adModeUnknown |
0 |
Valeur utilisée par défaut. Indique que les autorisations n'ont pas encore été définies ou ne peuvent pas être déterminées. |
adModeRead |
1 |
Lecture seule |
adModeWrite |
2 |
Écriture seule |
adModeReadWrite |
3 |
Lecture et écriture |
adModeShareDenyRead |
4 |
Ouverture en lecture interdite pour les utilisateurs autorisés en lecture seule |
adModeShareDenyWrite |
8 |
Ouverture interdite pour les utilisateurs autorisés en écriture seule |
adModeShareExclusive |
12 |
Ouverture interdite aux autres utilisateurs |
adModeShareDenyNone |
16 |
Les autres utilisateurs peuvent ouvrir en lecture/écriture |
Définir correctement cette propriété permet dans bien des cas de simplifier les éventuels conflits.
VII-A-4. Collection Errors▲
Toutes les erreurs de fournisseur créent un objet Error qui vient s'ajouter à la collection Errors de l'objet Connection. Il faut bien garder à l'esprit que ce ne sont que les erreurs du fournisseur, les autres erreurs ADO se gèrent de façon standard. Cette collection Errors se remplit pour une opération, si une erreur survient lors d'une opération suivante, l'ancienne collection est remplacée par la nouvelle.
Dans certains cas, le fournisseur envoie des avertissements dans la collection Errors, il est souvent conseillé de vider la collection Errors à l'aide de la méthode Clear avant d'utiliser les méthodes Resync, CancelBatch et UpdateBatch sur l'objet Recordset.
VII-A-5. Événements de connexion▲
À l'ouverture de la connexion, on peut décider si celle-ci s'ouvre de façon asynchrone en valorisant le paramètre « Options » de la méthode Open à adAsyncConnect.
Les événements de l'objet Connection sont :
BeginTransComplete, CommitTransComplete, et RollbackTransComplete pour les transactions
WillConnect, ConnectComplete et Disconnect pour l'ouverture et la fermeture
InfoMessage pour la gestion des erreurs
VII-A-5-a. WillExecute et ExecuteComplete▲
Ces événements se déclenchent avant et après l'exécution d'une commande, implicite ou non. En clair, ces événements se produisent sur l'appel de Connection.Execute, Command.Execute et Recordset.Open.
Private
Sub
Connection_WillExecute
(
Source As
String
, CursorType As
ADODB.CursorTypeEnum
, _
LockType As
ADODB.LockTypeEnum
, Options As
Long
, adStatus As
ADODB.EventStatusEnum
, ByVal
pCommand As
ADODB.Command
, _
ByVal
pRecordset As
ADODB.Recordset
, ByVal
pConnection As
ADODB.Connection
)
Private
Sub
Connection_ExecuteComplete
(
ByVal
RecordsAffected As
Long
, _
ByVal
pError As
ADODB.Error
, adStatus As
ADODB.EventStatusEnum
, _
ByVal
pCommand As
ADODB.Command
, ByVal
pRecordset As
ADODB.Recordset
, _
ByVal
pConnection As
ADODB.Connection
)
pConnection doit toujours contenir une référence à une connexion valide.
Si l'événement est dû à Connection.Execute, pCommand et pRecordset sont à « Nothing ».
Si l'événement est dû à Command.Execute, pCommand est la référence de l'objet Command et pRecordset vaut « Nothing ».
Si l'événement est dû à Recordset.Open, pCommand vaut « Nothing » et pRecordset est la référence de l'objet Recordset.
VII-B. L'objet Command▲
Pour ceux d'entre vous qui ont lu l'article « Utiliser le modèle ADOX avec Visual Basic » vous allez retrouver sensiblement le même chapitre, un peu plus étoffé et portant sur des axes différents.
Beaucoup de programmeurs n'utilisent pas l'objet Command avec ADO préférant travailler directement avec l'objet Recordset. Pourtant l'utilisation de cet objet peut être indispensable lorsqu'on souhaite travailler avec des requêtes paramétrées ou pour utiliser directement des requêtes actions. Nous allons donc aborder l'objet Command de façon assez détaillée sous l'angle suivant :
- Utilisation de Command pour utiliser des requêtes paramétrées
- Utilisation de Command avec des requêtes actions
Nous allons commencer par voir l'objet Command en détail.
VII-B-1. Généralités▲
Un objet command représente une commande spécifique à exécuter sur une source de données. Ceci peut être une instruction SQL ou une procédure stockée. Cet objet peut être une requête/procédure stockée dans la base ou créée à l'exécution. Un objet Command dépend toujours d'une connexion soit créée spécifiquement pour cette commande, soit d'une connexion déjà existante.
VII-B-2. Propriétés▲
ActiveConnection▲
Définit la connexion utilisée pour l'objet Command. Cette propriété doit être passée à Nothing avant de changer la connexion d'un objet Command. Comme les objets Command héritent de certaines propriétés de la connexion, faites attention au paramétrage de celle-ci.
CommandText▲
La propriété CommandText contient le texte de la commande à exécuter. Ce texte peut être le nom d'une requête stockée, une chaîne SQL, etc.
CommandTimeout▲
La valeur est en seconde. S'applique en général sur l'objet connection
CommandType▲
Donne le type de la commande. Cette propriété est très importante. En effet, il y aura une erreur récupérable si le paramètre donné est faux. De plus ne pas valoriser correctement cette propriété peut dégrader fortement les performances. Les valeurs peuvent êtres
Constante |
Valeur |
Description |
---|---|---|
adCmdText |
1 |
CommandText correspond à la définition textuelle d'une commande ou d'un appel de procédure stockée |
adCmdTable |
2 |
CommandText correspond au nom de table dont les colonnes sont toutes renvoyées par une requête SQL générée en interne. |
adCmdTableDirect |
512 |
CommandText correspond à un nom de table dont les colonnes sont toutes renvoyées. |
adCmdStoredProc |
4 |
CommandText correspond au nom d'une procédure stockée. |
adCmdUnknown |
8 |
Valeur utilisée par défaut. Le type de commande de la propriété CommandText est inconnu |
adCmdFile |
256 |
CommandText correspond au nom de fichier d'un Recordset permanent |
adExecuteNoRecords |
128 |
CommandText correspond à une commande ou une procédure stockée qui ne renvoie pas de ligne (par exemple, une commande qui insère uniquement des données). Si des lignes sont extraites, elles ne sont pas prises en compte et ne sont pas retournées. Toujours associée à adCmdText ou adCmdStoredProc |
Attention toutefois, une procédure stockée peut-être différemment interprétée selon les SGBD. Voir aussi la rubrique « Parameters ».
NamedParameters▲
Définit si le nom des paramètres est passé au fournisseur, ce qui lui permet de ne pas avoir à les interpréter dans l'ordre de leur création.
Prepared▲
Détermine si une commande doit être Précompilée. N'est utile que si la commande doit être exécutée plusieurs fois. Attention, certains fournisseurs n'acceptent pas cette modification sans toutefois déclencher d'erreur.
State▲
Renvoie l'état de la commande (ouverte ou fermée)
VII-B-3. Méthodes▲
Cancel▲
Annule l'exécution de la commande si celle-ci est asynchrone.
Execute▲
Execute la commande. De la forme :
command.Execute RecordsAffected, Parameters, Options
Où RecordsAffected renvoie le nombre d'enregistrements affectés par la commande. Ceci n'est vrai que pour une requête action ou pour l'appel d'une procédure d'action. Le paramètre n'est pas valorisé avec le nombre d'enregistrements extraits si la commande renvoie un recordset.
Parameters est un tableau contenant les paramètres (pour les requêtes/procédures paramétrées évidemment)
Option est identique a ce qui est décrit dans la méthode Open de l'objet Recordset.
Nous avons là plusieurs cas qui nous intéressent :
- On utilise toujours Command.Execute ou Connection.Execute pour utiliser des requêtes actions.
- Pour récupérer un recordset de l'objet Command, on peut soit passer la commande dans la méthode Open du recordset, soit affecter les enregistrements renvoyés dans un recordset.
Regardons le code suivant :
Dim
Cnn1 As
ADODB.Connection
, MonRs As
ADODB.Recordset
, MaCommand As
ADODB.Command
Set
Cnn1 =
New
ADODB.Connection
Cnn1.Open
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\biblio.mdb ;User Id=Admin; Password="
Set
MaCommand =
New
ADODB.Command
With
MaCommand
.ActiveConnection
=
Cnn1
.CommandText
=
"SELECT * FROM Authors"
Set
MonRs =
MaCommand.Execute
End
With
MonRs.Close
Set
MonRs =
Nothing
Set
MonRs =
New
ADODB.Recordset
MonRs.Open
MaCommand, , adOpenKeyset
, adLockOptimistic
, adCmdText
J'utilise les deux méthodes que je vous ai données plus haut. Notez toutefois que dans le Command.Execute je n'ai pas défini le curseur. J'obtiens donc un curseur côté serveur en avant seulement et en lecture seule. Supposons que je paramètre mon Recordset au préalable :
Set
MonRs =
New
ADODB.Recordset
With
MonRs
.CursorLocation
=
adUseClient
.CursorType
=
adOpenStatic
.LockType
=
adLockOptimistic
End
With
Set
MonRs =
MaCommand.Execute
J'obtiendrais pourtant le même curseur qu'avec le code précédent. Cela vient du fait que lors de la création d'un recordset à l'aide de la méthode Execute, que ce soit sur l'objet Connection ou sur l'objet Command, hérite d'un curseur défini par la connexion. Selon la valeur de la propriété CursorLocation de l'objet Connection, vous obtiendrez soit un curseur en avant seulement en lecture seule (serveur) soit un curseur statique en lecture seule (Client). Le recordset sera toujours en lecture seule.
CreateParameter▲
Sert à créer un paramètre (voir explications plus loin).
De la forme command.CreateParameter (Name, Type, Direction, Size, Value)
Attention à ne pas faire une erreur courante avec cette méthode. Celle-ci crée un paramètre, mais ne l'ajoute pas à la collection Parameters de l'objet Command. Ceci est d'ailleurs indispensable afin de pouvoir valoriser d'autres propriétés avant l'ajout.
VII-B-4. Collection Parameters▲
Généralités▲
Il faut déjà faire attention, pour les utilisateurs d'autres SGBD qu'Access à bien faire la différence entre procédure stockée et requête paramétrée.
Quoique regroupés dans la même collection, il existe deux types de paramètres. Les paramètres d'entrée, attendus par la procédure/requête pour pouvoir s'exécuter, et les paramètres de sorties qui peuvent être renvoyés par une procédure. Il convient de faire attention avec ceux-ci, une connection n'acceptant jamais plus de deux objets Command ayant des paramètres de sorties.
Quelques méthodes de la collection▲
Append
Ajoute un paramètre à la collection. De la forme
Command.Parameters .Append Name, Type, DefinedSize, Attrib
Il est possible d'utiliser la méthode CreateParameter dans le Append. Vous devez avoir typé votre paramètre avant ou lors de l'ajout à la collection. Il est préférable de valoriser votre paramètre avant de l'ajouter à la collection afin de ne pas solliciter le fournisseur.
Delete
Enlève un paramètre de la collection. On doit spécifier soit le nom, soit l'index du paramètre à retirer.
VII-B-5. Objet Parameter▲
Propriétés▲
Attributes
Précise si le paramètre accepte les valeurs signées, binaires ou NULL.
Direction
Définit si le paramètre est un paramètre d'entrée, de sortie ou de retour. Attention de ne pas confondre un paramètre de retour(adParamReturnValue) qui est l'entier éventuellement renvoyé par une procédure (dans le Return) d'un paramètre de sortie (adParamOutput) qui est le paramètre renvoyé par une procédure.
Name
Définit le nom du paramètre. N'est pas obligatoire
NumericScale
Donne la précision (nombre de chiffres à droite de la virgule) d'un paramètre numérique.
Size
Donne la taille en octet d'un paramètre dont le type est potentiellement de longueur variable (par exemple String). Ce paramètre est obligatoire pour les types de longueur indéterminée (String, Variant).
Elle doit être toujours valorisée avant ou lors de l'ajout à la collection.
Type
Comme son nom l'indique !
Ne vous emmêlez pas les pinceaux entre les chaînes adVarChar et les chaînes Unicode adVarWChar
Value
De manière générale, valorisez cette propriété après l'ajout à la collection.
Méthode▲
AppendChunk
Permet d'accéder aux textes ou binaires longs.
VII-B-6. Exemple▲
Requêtes paramétrées▲
Nous allons voir ici un exemple d'utilisation de requête paramétrée.
Prenons la requête stockée nommée ReqFerie définie comme :
PARAMETERS DateCib DateTime;
SELECT
tblFerie.DateFer
FROM tblFerie
WHERE (((
tblFerie.DateFer
)>
DateValue
(
[DateCib])))
ORDER BY tblFerie.DateFer
;
La fonction suivante crée un recordset en utilisant l'objet Command.
Private
Sub
Command5_Click
(
)
Dim
cnn1 As
ADODB.Connection
, Comm1 As
ADODB.Command
, Param1 As
Parameter, MonRecordset As
ADODB.Recordset
Set
cnn1 =
New
ADODB.Connection
With
cnn1
.Provider
=
"Microsoft.Jet.OLEDB.4.0;"
.ConnectionTimeout
=
30
.CursorLocation
=
adUseClient
.IsolationLevel
=
adXactChaos
.Mode
=
adModeShareExclusive
.Properties
(
"Jet OLEDB:System database"
) =
"D:\User\jmarc\tutorial\ADOX\system.mdw"
.Open
"Data Source=D:\User\jmarc\tutorial\ADOX\baseheb.mdb ;User Id=Admin; Password="
End
With
Set
Comm1 =
New
ADODB.Command
With
Comm1
.ActiveConnection
=
cnn1
.CommandType
=
adCmdStoredProc
.CommandText
=
"ReqFerie"
End
With
Set
Param1 =
New
Parameter
With
Param1
.Direction
=
adParamInput
.Type
=
adDate
.Name
=
"DateCib"
End
With
Comm1.Parameters.Append
Param1
Comm1
(
"DateCib"
).Value
=
#1
/
1
/
2002
#
Set
MonRecordset =
Comm1.Execute
End
Sub
Requête action▲
On peut aussi utiliser aussi l'objet Command pour exécuter des requêtes actions sur la source de données. En général, comme celles-ci sont rarement utilisées plusieurs fois dans le même code, on utilise plus souvent l'objet Connection, ce qui permet de tout passer dans une ligne, tel que :
Cnn1.Execute
"DELETE * FROM Authors WHERE [year Born]=1938"
, , adExecuteNoRecords
Néanmoins on peut aussi utiliser l'objet Command.
With
Comm1
.ActiveConnection
=
cnn1
.CommandType
=
adCmdText
.CommandText
=
"UPDATE Authors SET [Year Born]= [Year Born]+1"
End
With
Comm1.Execute
On trouve par contre beaucoup plus souvent l'usage de requête stockée paramétrée avec l'objet command. Par exemple:
Dim
cnn1 As
ADODB.Connection
, Comm1 As
ADODB.Command
, Param1 As
Parameter, Param2 As
Parameter, MonRecordset As
ADODB.Recordset
Set
cnn1 =
New
ADODB.Connection
With
cnn1
.Provider
=
"Microsoft.Jet.OLEDB.4.0;"
.ConnectionTimeout
=
30
.CursorLocation
=
adUseClient
.Open
"Data Source=D:\basehebdo.mdb ;User Id=Admin; Password="
End
With
cnn1.BeginTrans
Set
Comm1 =
New
ADODB.Command
With
Comm1
.ActiveConnection
=
cnn1
.CommandType
=
adCmdText
.CommandText
=
"PARAMETERS DateCib DateTime, BancCib Text;"
&
_
"DELETE * From tblAnomalie WHERE tblAnomalie.NumBanc=[BancCib] AND tblAnomalie.DatDimanche>=[DateCib];"
.NamedParameters
=
True
End
With
Set
Param1 =
New
Parameter
With
Param1
.Direction
=
adParamInput
.Type
=
adDate
.Name
=
"DateCib"
End
With
Set
Param2 =
New
Parameter
With
Param2
.Direction
=
adParamInput
.Type
=
adVarWChar
.Size
=
3
.Name
=
"BancCib"
End
With
Comm1.Parameters.Append
Param1
Comm1.Parameters.Append
Param2
Comm1
(
"BancCib"
).Value
=
"S01"
Comm1
(
"DateCib"
).Value
=
#1
/
1
/
2002
#
Comm1.Execute
If
MsgBox
(
"valider la transaction"
, vbYesNo
) =
vbYes
Then
cnn1.CommitTrans
Else
cnn1.RollbackTrans
End
If
L'avantage de ce genre d'utilisation repose sur le fait qu'un nouvel appel d'Execute avec de nouvelles valeurs de paramètres est immédiatement accessible. Ainsi
Comm1.Execute
, Array
(
#1
/
1
/
2002
#, "S04"
), adCmdText
+
adExecuteNoRecords
Est une réutilisation aisée de ma commande.