Voir le flux RSS

Pierre Fauconnier

VBA Excel - Access : Interactions entre Excel et Access avec ADODB : Manipulation des enregistrements (2)

Note : 3 votes pour une moyenne de 3,33.
par , 25/08/2019 à 10h22 (1209 Affichages)
Dans le premier billet traitant des échanges Excel-Access par ADODB, j'ai développé un framework générique qui permet de réaliser les quatre actions CRUD sur une base de données (Create, Read, Update, Delete).

Après ce billet théorique, je passe à la pratique avec la création d'une DAL spécifique pour les manipulations des données d'une table. Dans une architecture "trois-tiers", ce module standard spécifique fait partie de la couche d'accès aux données. C'est au travers de ce module spécifique que la DAL générique sera utilisée.

Base de données utilisée

Pour l'exemple, j'ai créé une base de données dans laquelle se trouve une seule table. En effet, pour mettre en place les mécanismes d'échange ADODB, nul besoin de requêtes bien complexes, de jointures ou autres. Le code SQL à générer ne viendrait que compliquer la démarche, mais ce qui est illustré ici fonctionne aussi bien avec des requêtes complexes.

Table Contact

Une seule table, donc, la table des contacts:
  • ContactPK : clé primaire autoincrémentée, donc de type Long ;
  • FirstName : Prénom du contact, de type "Texte court" en Access ;
  • LastName : Nom du contact, de type "Texte court" ;
  • BirthDate : Date de naissance du contact, de type "Date/Heure" ;
  • Amount : Montant, de type Réel double ;
  • Active : Contact actif ou pas, de type booléen.


Avec ces données, nous manipulerons les types les plus souvent utilisés.

Dal spécifique pour la gestion des contacts

Tout comme j'ai nommé la dal générique DAL, chaque dal spécifique sera elle aussi nommée. Pour gérer les contacts, je place donc tous les codes qui vont suivre dans un module standard nommé DalContact.


Structure Contact

Pour faciliter la manipulation des données d'un contact, j'ai créé une structure (Type... End Type). On pourrait s'en passer, ou utiliser un tableau (une structure est en fait un tableau), un objet personnalisé. Ce n'est pas important ici, le principal étant de voir la simplicité avec laquelle on manipule les données de la base si l'on prend la peine de systématiser son approche.

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
Type Contact
  ID As Long
  FirstName As String
  LastName As String
  BirthDate As Date
  Amount As Double
  Active As Boolean
End Type

Conseil : Peuplez votre table de quelques données avant de continuer la lecture du billet.

Récupération de toutes les données

La magie de l'abstraction va commencer à opérer ici. Bien sûr, vous devez connaître la syntaxe SQL et la structure de la table pour créer votre requête*.

Si l'on veut récupérer tous les contacts de la table Contact, on doit utiliser une requête Select * from Contact. Personnellement, je préfère nommer tous les champs, ce qui me permet de savoir comment le tableau de retour sera constitué.

Le contrat de la DAL, c'est d'exposer un tableau (Array) constitué en lignes des enregistrements récupérés et en colonne les "champs" de la requête. La DAL générique développée dans le premier billet expose à cette fin la fonction GetRows(sql, [Parameters]. Dès lors, récupérer les données de tous les contacts revient à créer une fonction qui appelle simplement la dal générique en lui passant la requête SQL.

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
Function getRowsForAllItems()
  getRowsForAllItems = Dal.getRows("select contactpk, firstname, lastname, birthdate, amount, active from contact")
End Function

On remarque ici qu'aucune notion ADODB n'a été manipulée. Tout ce qui concerne ADODB est dans la DAL spécifique et uniquement Là. C'est en cela que réside l'abstraction.


En plaçant un point d'arrêt sur End Function, on peut remarquer la variable locale constituée du tableau des enregistrements récupérés.

Nom : 2019-08-25_083524.png
Affichages : 655
Taille : 37,0 Ko

Conseil : N'hésitez pas à réaliser toute l'opération en pas à pas (F8), de manière à bien voir le déroulement du code.

* Avec certains SGBD (système de gestion de base de données), il est possible de faire abstraction de la syntaxe SQL grâce aux procédures stockées, permettant au programmeur "métier" de programmer sans manipuler ADODB et SQL. Je parle de cette technique dans le quatrième billet, qui explique comment déporter le sql du côté de la base et s'en passer totalement dans le code VBA...

Récupérer les données d'un contact dans une structure

Pour récupérer les données d'un contact dans la structure vue plus haut, il suffit de connaître la syntaxe sql requise. Ici, nous avons besoin d'un paramètre (la clé primaire), et à nouveau, la DAL générique va nous aider à manipuler cela sans avoir besoin de savoir que nous faisons de l'ADODB. Ce paramètre requis étant la clé primaire, il s'agit donc d'un entier long (4 octets) qu'il faudra renseigner comme paramètre.

La syntaxe SQL pour Access nécessaire pour la récupération du contact est select contactpk, firstname, lastname, birthdate, amount, active from contact where contactpk = ?. Ici, le paramètre est représenté par le signe ?. Il convient donc d'ajouter un paramètre à la commande, ce qui est prévu par la DAL générique qui peut recevoir une collection d'objets ADODB.Parameters.

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Function getItem(ID As Long) As Contact
  Dim Record
  Dim Command As String
  Dim Parameters As New Collection
 
  Command = "select contactpk, firstname, lastname, birthdate, amount, active from contact where contactpk = ?"
  Parameters.Add Dal.getParameter("P1", adInteger, adParamInput, 4, ID)
  Record = Dal.getRows(Command, Parameters)
  With getItem
    .ID = Record(0, 0)
    .FirstName = Record(0, 1)
    .LastName = Record(0, 2)
    .BirthDate = Record(0, 3)
    .Amount = Record(0, 4)
    .Active = Record(0, 5)
  End With
End Function

Je pense que le code parle de lui-même et se passe de beaucoup d'explications. Ici aussi, on remarque à nouveau qu'aucune notion ADODB n'est pilotée. Les notions liées au paramètre (Type, direction, longueur) ne sont pas à proprement parler des notions ADODB, mais des notions SQL liées à la façon dont les requêtes et procédures stockées paramétrées sont manipulées côté SQL.

L'examen du code en pas à pas permet de voir qu'à la fin de la fonction GetItem, une structure contient bien les infos du contact recherché.

Nom : 2019-08-25_084922.png
Affichages : 647
Taille : 29,3 Ko

Remarque : il est intéressant de noter ici qu'il y a un contrat avec la DAL. La DAL renvoie un tableau formaté d'une certaine manière. Si l'on change de SGBD, la DAL doit continuer à respecter le contrat d'exposer un tableau formaté comme attendu. Le respect de ces contrats est à la base même de la programmation sous architecture "trois-tiers" où les modifications internes d'une couche ne peuvent pas impacter les autres couches de l'application développée. En bémol à cette volonté irréaliste, on notera que, les SGBD ne respectant pas scrupuleusement les normes SQL en vigueur, il y a fort à parier qu'il faudra adapter le texte des requêtes SQL en fonction du SGDB utilisé.


Suppression d'un contact

Pour supprimer un contact, il suffit d'une requête SQL de suppression delete from Contact where contactpk = ?. Ici, à nouveau, pas de manipulations ADODB.

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
Sub Delete(ID As Long)
  Dim Command As String
  Dim Parameters As New Collection
 
  Command = "delete from Contact where contactpk = ?"
  Parameters.Add Dal.getParameter("P1", adInteger, adParamInput, 4, ID)
  Dal.Execute Command, Parameters
End Sub

Création d'un contact dans la DB

Grâce à la DAL générique, nous pouvons créer un contact sans notions ADODB en utilisant la procédure de la DAL générique que nous avons déjà utilisée pour la suppression.

Ici, nous allons devoir passer 5 paramètres, à savoir les variables de la structure Contact. Comme c'est la DB qui attribue la clé primaire, nous ne pouvons pas la passer à la DAL. Par contre, il sera utile de la récupérer, ce que permet la DAL générique grâce à l'argument optionnel CreateCommand et au fait que Execute renvoie un entier long.

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Private Function Create(item As Contact) As Long
  Dim Command As String
  Dim Parameters As New Collection
 
  Command = "insert into contact (firstname, lastname, birthdate, amount, active) values(?,?,?,?,?)"
  With item
    Parameters.Add Dal.getParameter("P1", adVarChar, adParamInput, 255, .FirstName)
    Parameters.Add Dal.getParameter("P2", adVarChar, adParamInput, 255, .LastName)
    Parameters.Add Dal.getParameter("P3", adDate, adParamInput, 255, .BirthDate)
    Parameters.Add Dal.getParameter("P4", adDouble, adParamInput, 255, .Amount)
    Parameters.Add Dal.getParameter("P5", adBoolean, adParamInput, 255, .Active)
  End With
  Create = Dal.Execute(Command, Parameters, True)
End Function

Attention : Access ne gère pas les paramètres nommés, de sorte qu'il est impératif que les paramètres soient créés dans l'ordre des ? mentionnés dans la requête SQL.

Note : Si vous êtes observateur, vous aurez vu que cette fonction est Private. En effet, j'ai choisi de passer par une fonction publique Save qui décidera s'il s'agit de création ou de modification.

Modification des données d'un contact

Pour modifier les données d'un contact, nous avons besoin d'une requête [c/]Update...[/c]. Ici, nous utilisons la clé primaire. Notez que la syntaxe SQL impose qu'elle soit le 6e argument (6e signe ?), et donc, dans l'ajout des paramètres à la commande, ce paramètre est ajouté en dernier.

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Private Function Update(item As Contact)
  Dim Command As String
  Dim Parameters As New Collection
 
  Command = "update contact set firstname = ?, lastname = ?, birthdate = ?, amount = ?, active = ? where contactpk = ?"
  With item
    Parameters.Add Dal.getParameter("P1", adVarChar, adParamInput, 255, .FirstName)
    Parameters.Add Dal.getParameter("P2", adVarChar, adParamInput, 255, .LastName)
    Parameters.Add Dal.getParameter("P3", adDate, adParamInput, 255, .BirthDate)
    Parameters.Add Dal.getParameter("P4", adDouble, adParamInput, 255, .Amount)
    Parameters.Add Dal.getParameter("P5", adBoolean, adParamInput, 255, .Active)
    Parameters.Add Dal.getParameter("P6", adInteger, adParamInput, 255, .ID)
  End With
  Dal.Execute Command, Parameters
End Function

Ici aussi, la fonction est Private

Create ou Update?

Afin de permettre d'enregistrer un contact sans se soucier de le créer ou de le modifier, je manipule ces deux fonctions privées au travers d'une fonction publique Save

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
Function Save(item As Contact) As Long
  If item.ID = 0 Then
    Save = Create(item)
  Else
    Update item
  End If
End Function

Ce n'est pas obligatoire, bien sûr, mais je pratique ainsi depuis longtemps... Il est intéressant de noter ici que l'ajout (Create), la modification (Update) et la suppression (Delete) utilisent la même fonction de la DAL générique. On gagne du code par une capitalisation élevée du code existant.


Et si on doit manipuler les données d'une autre table?
Si je dois manipuler par exemple des données liées à une localité, je vais créer une structure ou un objet City et une dal spécifique DalCity. Se créer une dal spécifique modèle peut aider dans ce cas. Et je manipulerai les données de la table City au travers de cette dal spécifique.

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Option Explicit
 
Type City
  ID As Long
  CityName As String
  ZipCode As String
  CountryID As Long
End Type
 
Function getRowsForAllItems()
  getRowsForAllItems = Dal.getRows("select citypk, CityName, ZipCode, CountryFK from city")
End Function
 
Function getItem(ID As Long) As City
  Dim Record
  Dim Command As String
  Dim Parameters As New Collection
 
  Command = "select Citypk, CityName, ZipCode, CountryFK from City where CityPk = ?"
  Parameters.Add Dal.getParameter("P1", adInteger, adParamInput, 4, ID)
  Record = Dal.getRows(Command, Parameters)
  With getItem
    .ID = Record(0, 0)
    .CityName = Record(0, 1)
    .ZipCode = Record(0, 2)
    .CountryID = Record(0, 3)
  End With
End Function

On remarque ici que j'utilise les mêmes noms de fonctions que dans DalContact. Là aussi, il s'agit de systématiser son approche. Dès lors, il ne faut pas oublier de préfixer les procédures et fonctions du nom de la dal spécifique que l'on doit manipuler.

En testant le code vu plus haut qui a été créé en quelques minutes, on obtient bien les données des localités.

Nom : 2019-08-25_091808.png
Affichages : 653
Taille : 40,4 Ko

Nom : 2019-08-25_091848.png
Affichages : 652
Taille : 49,6 Ko




Conclusions

La DAL spécifique permet d'isoler les procédure et fonctions qui manipulent une table au sein de la base. Ce sont bien entendu les besoins métier qui vous feront développer d'autres fonctions au sein du module pour manipuler les données de la table de façon plus spécifique en fonction de vos besoins.

La DAL générique est le seul module qui contient du code manipulant explicitement des notions ADODB. Au sein de toute votre application, c'est uniquement dans ce module que vous devrez manipuler ADODB. C'est en cela que c'est une "couche d'abstraction", car elle permet au développeur de créer son code en faisant abstraction de ces notions ADODB.

Systématiser cette approche dans vos développements vous fera gagner énormément de temps.

Dans le troisième billet, j'expose la manipulation de ces données au travers d'un userform.

Envoyer le billet « VBA Excel - Access : Interactions entre Excel et Access avec ADODB : Manipulation des enregistrements (2) » dans le blog Viadeo Envoyer le billet « VBA Excel - Access : Interactions entre Excel et Access avec ADODB : Manipulation des enregistrements (2) » dans le blog Twitter Envoyer le billet « VBA Excel - Access : Interactions entre Excel et Access avec ADODB : Manipulation des enregistrements (2) » dans le blog Google Envoyer le billet « VBA Excel - Access : Interactions entre Excel et Access avec ADODB : Manipulation des enregistrements (2) » dans le blog Facebook Envoyer le billet « VBA Excel - Access : Interactions entre Excel et Access avec ADODB : Manipulation des enregistrements (2) » dans le blog Digg Envoyer le billet « VBA Excel - Access : Interactions entre Excel et Access avec ADODB : Manipulation des enregistrements (2) » dans le blog Delicious Envoyer le billet « VBA Excel - Access : Interactions entre Excel et Access avec ADODB : Manipulation des enregistrements (2) » dans le blog MySpace Envoyer le billet « VBA Excel - Access : Interactions entre Excel et Access avec ADODB : Manipulation des enregistrements (2) » dans le blog Yahoo

Mis à jour 29/09/2019 à 22h32 par Pierre Fauconnier

Catégories
VBA , Excel , MS Office , Bonnes pratiques , Access

Commentaires