Définition et manipulation de données avec DAO

Christophe WARIN

Ce support constitue un cours d'introduction à l'accés aux données dans une base Access via DAO (Data Access Object). Il ne nécessite pas de connaissance pointue en programmation hormis les bases du langage VBA.

Commentez

- Titre : Définition et manipulation de données avec DAO

- Auteur : Christophe WARIN

- Parution : 9 mai 2005

- Mise à jour : 30 juillet 2009

- Licence : Copyright ® 2005 WARIN Christophe. 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.

Sommaire

- 1. Introduction & Téléchargement

- 1-1. Téléchargement

- 1-2. Introduction

- 2. La hiérarchie du modèle DAO

- 2-1. Le modèle objet

- 2-2. Quelques rappels sur les collections

- 2-2-1. Accéder à un élément d'une collection

- 2-2-2. Compter les éléments

- 2-2-3. Parcourir les éléments d'une collection

- 2-2-4. Ajouter un élément

- 2-2-5. Supprimer un élément

- 3. Accèder à une base de données

- 3-1. L'objet DBEngine

- 3-1-1. Généralités

- 3-1-2. Liste des propriétés

- 3-1-2-1. DefaultPassword

- 3-1-2-2. DelfaultType

- 3-1-2-3. DefaultUser

- 3-1-2-4. Errors

- 3-1-2-5. Inipath

- 3-1-2-7. Properties

- 3-1-2-8. SystemDB

- 3-1-2-9. Version

- 3-1-2-10. Workspaces

- 3-1-3. Liste des méthodes

- 3-1-3-1. BeginTrans

- 3-1-3-2. CommitTrans

- 3-1-3-3. CompactDatabase

- 3-1-3-4. CreateDatabase

- 3-1-3-5. CreateWorkspace

- 3-1-3-6. Idle

- 3-1-3-7. OpenDatabase

- 3-1-3-8. RepairDatabase

- 3-1-3-9. Rollback

- 3-2. L'objet Workspace

- 3-2-1. Généralités

- 3-2-2. Liste des propriétés

- 3-2-2-1. Databases

- 3-2-2-2. IsolateODBCTrans

- 3-2-2-3. Name

- 3-2-2-4. Properties

- 3-2-2-5. Type

- 3-2-3. Liste des méthodes

- 3-2-3-1. BeginTrans

- 3-2-3-2. Close

- 3-2-3-3. CommitTrans

- 3-2-3-4. CreateDatabase

- 3-2-3-5. OpenDatabase

- 3-2-3-6. Rollback

- 3-2-4. Accéder à un groupe de travail spécifique

- 3-3. L'objet Database

- 3-3-1. Généralités

- 3-3-1-1. La méthode CurrentDb

- 3-3-1-2. La méthode CodeDb

- 3-3-2. Liste des propriétés

- 3-3-2-1. CollatingOrder

- 3-3-2-2. Connect

- 3-3-2-3. Containers

- 3-3-2-4. Name

- 3-3-2-5. Properties

- 3-3-2-6. QueryDefs

- 3-3-2-7. RecordsAffected

- 3-3-2-8. Recordsets

- 3-3-2-9. Relations

- 3-3-2-10. TableDefs

- 3-3-2-11. Transactions

- 3-3-2-12. Updatable

- 3-3-2-13. Version

- 3-3-3. Liste des méthodes

- 3-3-3-1. Close

- 3-3-3-2. CreateProperty

- 3-3-3-3. CreateQueryDef

- 3-3-3-4. CreateRelation

- 3-3-3-5. CreateTableDef

- 3-3-3-6. Execute

- 3-3-3-7. NewPassword

- 3-3-3-8. OpenRecordset

- 4. DAO et la structure d'une base de données

- 4-1. Généralités

- 4-2. Les propriétés spécifiques

- 4-2-1. Définitions

- 4-2-2. Liste des propriétés d'un objet Property

- 4-2-2-1. Inherited

- 4-2-2-2. Name

- 4-2-2-3. Type

- 4-2-2-4. Value

- 4-2-3. Accéder à une propriété

- 4-2-4. Modifier la valeur d'une propriété

- 4-2-5. Création d'une nouvelle propriété

- 4-3. L'objet TableDef

- 4-3-1. Définitions

- 4-3-2. Liste des propriétés

- 4-3-2-1. Attributes

- 4-3-2-2. Connect

- 4-3-2-3. DataCreated

- 4-3-2-4. Fields

- 4-3-2-5. Indexes

- 4-3-2-6. LastUpdated

- 4-3-2-7. Name

- 4-3-2-8. Properties

- 4-3-2-9. RecordCount

- 4-3-2-10. SourceTableName

- 4-3-2-11. Updatable

- 4-3-2-12. ValidationRule

- 4-3-2-13. ValidationText

- 4-3-3. Liste des méthodes

- 4-3-3-1. CreateField

- 4-3-3-2. CreateIndex

- 4-3-3-3. CreateProperty

- 4-3-3-4. OpenRecordset

- 4-3-3-5. RefreshLink

- 4-3-4. Opérations sur les tables d'une base de données

- 4-3-4-1. Lister les tables d'une base de données

- 4-3-4-2. Renommer une table

- 4-3-4-3. Supprimer une table

- 4-3-4-4. Créer une nouvelle table

- 4-4. L'objet Field

- 4-4-1. Définition

- 4-4-2. Liste des propriétés

- 4-4-2-1. AllowZeroLength

- 4-4-2-2. Attributes

- 4-4-2-3. CollatingOrder

- 4-4-2-4. DataUpdatable

- 4-4-2-5. DefaultValue

- 4-4-2-6. FieldSize

- 4-4-2-7. ForeignName

- 4-4-2-8. Name

- 4-4-2-9. OrdinalPosition

- 4-4-2-10. Properties

- 4-4-2-11. Required

- 4-4-2-12. Size

- 4-4-2-13. SourceField

- 4-4-2-14. SourceTable

- 4-4-2-15. Type

- 4-4-2-16. ValidationRule

- 4-4-2-17. ValidationText

- 4-4-2-18. Value

- 4-4-2-19. VisibleValue

- 4-4-3. Liste des méthodes

- 4-4-3-1. AppendChunk

- 4-4-3-2. CreateProperty

- 4-4-3-3. GetChunk

- 4-4-4. Opérations sur les champs d'un objet TableDef

- 4-4-4-1. Renommer un champ

- 4-4-4-2. Supprimer un champ

- 4-4-4-3. Créer un champ

- 4-4-4-4. Dupliquer un champ

- 4-5. L'objet Index

- 4-5-1. Définitions

- 4-5-2. Liste des propriétés

- 4-5-2-1. DistinctCount

- 4-5-2-2. Fields

- 4-5-2-3. Foreign

- 4-5-2-4. IgnoreNulls

- 4-5-2-5. Name

- 4-5-2-6. Properties

- 4-5-2-7. Required

- 4-5-2-8. Unique

- 4-5-3. Liste des méthodes

- 4-5-3-1. CreateField

- 4-5-3-2. CreateProperty

- 4-5-4. Opérations sur les Index

- 4-5-4-1. Créer un index

- 4-5-4-2. Supprimer une clé primaire

- 4-6. L'objet Relation

- 4-6-1. Définitions

- 4-6-2. Liste des propriétés

- 4-6-2-1. Attributes

- 4-6-2-2. Fields

- 4-6-2-3. ForeignTable

- 4-6-2-4. Name

- 4-6-2-6. Properties

- 4-6-2-7. Table

- 4-6-3. Liste des méthodes

- 4-6-4. Exemple de définition des propriétés

- 4-6-5. Opérations sur les relations

- 4-6-5-1. Créer une relation

- 4-6-5-2. Compter les relations utilisant un champ donné

- 4-6-5-3. Supprimer les relations autour d'une table

- 4-7. L'objet QueryDef

- 4-7-1. Définitions

- 4-7-2. Liste des propriétés

- 4-7-2-1. Connect

- 4-7-2-2. DateCreated

- 4-7-2-3. Fields

- 4-7-2-4. LastUpdated

- 4-7-2-5. MaxRecords

- 4-7-2-6. Name

- 4-7-2-7. Parameters

- 4-7-2-8. Properties

- 4-7-2-9. RecordsAffected

- 4-7-2-10. ReturnsRecords

- 4-7-2-11. SQL

- 4-7-2-12. Type

- 4-7-2-13. Updatable

- 4-7-3. Liste des méthodes

- 4-7-3-1. CreateProperty

- 4-7-3-2. Execute

- 4-7-3-3. OpenRecordset

- 4-7-4. Opérations sur les requêtes

- 4-7-4-1. Création d'une requête

- 4-7-4-2. Modifier le code d'une requête

- 4-7-4-3. Lister les requêtes

- 5. Accès aux données

- 5-1. Définition

- 5-1-1. Les différents types de Recordset

- 5-2. Ouvrir et fermer un recordset

- 5-2-1. Depuis un objet Database

- 5-2-2. Depuis un objet QueryDef

- 5-2-3. Depuis un formulaire Access

- 5-2-4. Fermer un Recordset

- 5-3. Positions et déplacements

- 5-3-1. Se déplacer dans un Recordset

- 5-3-2. Trouver un enregistrement

- 5-3-3. Mémoriser une position

- 5-4. Manipulation des données

- 5-4-1. Lire un enregistrement

- 5-4-2. Modifier un enregistrement

- 5-4-3. Ajouter un enregistrement

- 5-4-4. Supprimer un enregistrement

- 5-4-5. Compter les enregistrements

- 5-4-6. Filtrer les données

- 5-5. Lecture par bloc

- 5-5-1. Généralités

- 5-5-2. Exemple

- 5-6. Liste des propriétés

- 5-6-1. AbsolutePosition

- 5-6-2. BOF

- 5-6-3. Bookmark

- 5-6-4. Bookmarkable

- 5-6-5. CacheSize

- 5-6-6. CacheStart

- 5-6-7. Connection

- 5-6-8. DataCreated

- 5-6-9. EditMode

- 5-6-10. EOF

- 5-6-11. Fields

- 5-6-12. Filter

- 5-6-13. Index

- 5-6-14. LastModified

- 5-6-15. LastUpdated

- 5-6-16. LockEdits

- 5-6-17. Name

- 5-6-18. NoMatch

- 5-6-19. PercentPosition

- 5-6-20. Properties

- 5-6-21. RecordCount

- 5-6-22. Restartable

- 5-6-23. Sort

- 5-6-24. StillExecuting

- 5-6-25. Transactions

- 5-6-26. Type

- 5-6-27. Updatable

- 5-6-28. UpdateOptions

- 5-6-29. ValidationRule

- 5-6-30. ValidationText

- 5-7. Liste des méthodes

- 5-7-1. AddNew

- 5-7-2. CancelUpdate

- 5-7-3. Clone

- 5-7-4. Close

- 5-7-5. CreateQueryDef

- 5-7-6. Delete

- 5-7-7. Edit

- 5-7-8. FindFirst, FindLast, FindNext, FindPrevious

- 5-7-9. GetRows

- 5-7-10. Move, MoveFirst, MoveLast, MoveNext, MovePrevious

- 5-7-11. OpenRecordset

- 5-7-12. Requery

- 5-7-13. Update

- 6. Conclusion

1 - Introduction & Téléchargement

1-1 - Téléchargement

Français

Télécharger la version PDF de ce tutoriel 96 pages - 547 Ko
FTP (Recommandé) : Télécharger
HTTP (Secours) : Télécharger

Arabe

Télécharger la traduction de ce tutoriel au format PDF 116 pages - 940 Ko par MED ALAOUI SOSSE
FTP (Recommandé) : Télécharger
HTTP (Secours) : Télécharger

1-2 - Introduction

DAO (Data Access Objects) est une bibliothèque regroupant un ensemble d'objets permettant d'accéder à une base de données. L'utilisation de ces objets permet à la fois de travailler la structure de la base mais aussi de manipuler ses données.

Ce cours a pour objectif de vous enseigner les innombrables possibilités offertes par cette bibliothèque, que ce soit aussi bien au niveau de la structure que des données. Via plusieurs exemples, vous allez ainsi découvrir comment il est possible de créer une table, modifier ses champs, définir des relations, construire des requêtes, manipuler les données d'un formulaire, ajouter de nouveaux enregistrements, ...

Vous pourrez aussi retrouver chacune des propriétés et des méthodes propres à chaque objet dans un listing en fin de section. Bien entendu, cette liste ne prétend pas se substituer à l'aide Access qui, je vous le rappelle, reste la plus grande mine d'informations.

Certaines parties ne sont pas détaillées dans ce document car elles ne répondent pas à une utilisation classique de DAO avec le moteur Jet. Afin d'alleger ce cours, vous ne trouverez donc pas d'informations concernant :

- L'acccès aux données dans un environnement ODBC Direct

- La replication

- Les objets DAO ne concernant pas l'accès aux données (Sécurité, Utilisateur, Conteneur ....)

Avant de commencer :

L'ensemble des méthodes et des objets permettant l'accès aux données via DAO sont regroupés au sein d'une même librairie. Afin d'utiliser ces fonctionnalités, il vous faut donc ajouter la référence suivante à votre projet :

Microsoft DA0 3.5 Object Library pour Access 97.
Microsoft DA0 3.6 Object Library pour les versions utltérieures.
Microsoft Office 12.0 (14.0) Access Database Engine Object pour travailler avec des bases de données Access 2007 ou Access 2010.

Comment ajouter une référence ?
Depuis le menu Outils de l'éditeur Visual Basic, sélectionnez l'option Références. Cochez ensuite la case correspondante à la référence à ajouter.

2 - La hiérarchie du modèle DAO

2-1 - Le modèle objet

Voici une représentation du modèle objet DAO :

Comme vous pouvez le remarquer, le modèle objet DAO possède une structure hiérarchisée dont la racine est un objet DBEngine. Les relations de descendance sont de type un à plusieurs. Cela signifie que chaque objet parent possède une collection de chaque type d'objet enfant dont le nom est normalisé ainsi :

Nom de la collection = Type de l'objet enfant + "s"

Par exemple, l'objet DBEngine possède une collection d'objet Workspace. Cette collection est nommée Workspaces.

Précisons aussi que ce schéma a été réduit uniquement à la partie définition de données (en bleu) et à la partie manipulation de données (en vert). De plus, chaque branche a été réduite pour améliorer la lisibilité. Comme tout autre objet, un objet DAO possède un ensemble de propriétés (property). Celles ci sont regroupées dans une collection nommée properties propre à chaque objet. Voici un exemple du schéma réel à appliquer aux objets TableDef.

L'utilisation de DAO implique de nombreuses déclarations de variables. Ceci demande beaucoup de rigueur. Aussi je vous invite à consulter le tutoriel sur les conventions de nommage Visual Basic écrit par Jean-Philippe AMBROSINO : Les conventions typographiques en VBA (illustrées sur Access)

2-2 - Quelques rappels sur les collections

Etant donné que DAO est un modèle objet et qu'il utilise de nombreuses collections, je vous propose quelques rappels sur le traitement des collections d'objets sous Visual Basic.

2-2-1 - Accéder à un élément d'une collection

Il existe deux techniques afin d'accéder à un objet d'une collection :

Accès via l'index : Il s'agit d'utiliser la position de l'élément dans la collection en sachant que le premier possède l'index zéro.

Syntaxe :

MaCollection.Item(2)

Accès via la clé : Il s'agit d'utiliser le nom de l'élement lorsque celui-ci est connu.

Syntaxe :

MaCollection.Item ("MonItem")

La propriété Item est le membre par défaut des objets de type Collection. Vous pouvez donc utiliser indifféremment :

Syntaxe :

MaCollection.Item ("MonItem")

Ou :

Syntaxe :

MaCollection.("MonItem")

2-2-2 - Compter les éléments

Sous Visual Basic, les collections proposent la propriété Count qui renvoie le nombre d'objets dans la collection.

Syntaxe :

MaCollection.Count

Etant donné que le premier élément a pour index 0, on en conclut aisément que le dernier élément de la collection possède l'index : Count - 1

2-2-3 - Parcourir les éléments d'une collection

Une nouvelle fois, il est possible d'utiliser deux méthodes. La première consiste en une boucle sur l'index de la collection jusqu'au dernier élément.

Voici un exemple :

Dim i As Integer, nbMax As Integer
'Récupère le nombre de Workspace
nbMax = DBEngine.Workspaces.Count - 1
'Boucle sur l'index
For i = 0 To nbMax
'Affiche le nom de l'objet
MsgBox DBEngine.Workspaces(i).Name
Next i

La seconde méthode utilise une boucle For Each … In … Next pour parcourir un à un les objets de la collection.

Ainsi :

Dim oWks As DAO.Workspace
For Each oWks In DBEngine.Workspaces
'Affiche le nom de l'objet
MsgBox oWks.Name
Next oWks

Peut être traduit par :

Pour chaque objet Workspace de la collection Workspaces du DBEngine
Afficher le nom de l'objet
Fin Pour

Cette dernière méthode possède un avantage dans le cas de collections hétérogènes. Imaginons une collection d'objets O1 et O2. Pour parcourir uniquement les éléments de type O1, nous aurions par exemple :

Dim oTmpObjet as TypeO1
For Each oTmpObjet In MaCollection
'Traitement à effectuer
Next oTmpObjet

2-2-4 - Ajouter un élément

Les collections DAO sont munies de la méthode Append qui permet d'ajouter un élément. Sa syntaxe est la suivante :

MaCollection.Append MonObjet

Notons tout de même que pour être ajouté, l'objet doit être instancié auparavant, sans quoi il sera impossible de l'ajouter. De même, il est impossible d'ajouter un objet si un autre objet présent dans la collection possède le même nom. Vous trouverez de nombreux exemples de la méthode Append dans la suite de ce document.

2-2-5 - Supprimer un élément

La méthode Delete appliquée aux collections DAO permet de supprimer l'élément dont le nom est passé en paramètre. La syntaxe de cette méthode est la suivante :

MaCollection.Delete "MonItem"

3 - Accèder à une base de données

Ce chapitre est entièrement consacré à l'ouverture d'une base de données. Il vous fournira une liste de l'ensemble des propriétés et des méthodes de chaque objet utilisé ainsi que plusieurs exemples d'utilisation sous Visual Basic.

3-1 - L'objet DBEngine

3-1-1 - Généralités

L'objet DBEngine correspond au moteur de base de données. Il s'agit d'un composant logiciel qui interprète les requêtes que vous lui transmettez et interroge le fichier de base de données. Dans la plupart des cas, vous n'aurez jamais à l'instancier ni même à le contrôler puisque l'objet Access.Application possède une propriété DBEngine renvoyant le moteur de base de données actuellement utilisé. L'objet DBEngine propose dans ses propriétés la liste des espaces de travail (collection Workspaces) ainsi que d'autres propriétés relatives à la gestion des utilisateurs. Ces propriétés n'ont que peu d'intérêt dans le cas d'une utilisation normale sans gestion de sécurité. Toutefois, le moteur de base de données n'est pas à oublier puisque c'est lui qui encapsule les méthodes de transactions ainsi que les méthodes de réparation et de compactage de la base de données.

3-1-2 - Liste des propriétés

Vous trouverez ci-dessous l'ensemble des propriétés de l'objet DBEngine.

3-1-2-1 - DefaultPassword

Type : String

Il s'agit du mot de passe par défaut qui sera utilisé lors de la création d'un nouvel objet Workspace.

3-1-2-2 - DelfaultType

Type : Long

Cette propriété correspond au type par défaut des futurs objets Workspace. Les valeurs possibles sont dbUseJet dans le cas d'une utilisation Jet et dbUseODBC dans le cas d'une liaison ODBC direct. Notons que dans ce dernier cas, l'objet Database est remplacé par un objet de type Connection.

3-1-2-3 - DefaultUser

Type : String

Il s'agit du nom d'utilisateur qui sera utilisé par défaut lors de la création d'un nouvel objet Workspace. Cette propriété est généralement utilisée en même temps que DefaultPassword.

3-1-2-4 - Errors

Type : Collection

Cette collection regroupe l'ensemble des erreurs levées par le moteur de base de données. Une erreur DAO est identifiée par un numéro d'erreur et possède une description correspondant au message d'erreur. A chaque fois qu'une opération DAO échoue,un ou plusieurs objets Error sont créés et ajoutés à la collections Errors. Une fois que tous ces objets sont créés, une erreur d'exécution est levée par VBA. Cette erreur correspond à l'objet Error possédant le numéro d'erreur le plus élevé. Sous Access, lors d'une erreur DAO, un seul objet Error est créé pour réprésenter l'erreur. L'erreur levée par VBA est donc la même que celle du moteur de base de données. Toutefois, si vous tentez par exemple de vous connecter à une base de données Oracle via votre application, il se peut qu'Oracle lève plusieurs objets Error reprénsentant la même erreur. Vous trouverez donc dans la collection DBEngine.Errors :

- L'ensemble des erreurs Oracle

- Une erreur Odbc

Mais une seule erreur sera levée par VBA. Le parcours de la collection Errors peut donc vous permettre d'affiner vos routines de gestion d'erreur.

3-1-2-5 - Inipath

Type : String

La propriété Inipath correspond au chemin du fichier d'initialisation du moteur de base de données. Il s'agit généralement d'une entrée dans la base des registres :
HKLM\Software\microsoft\Office\10.0\Access\Jet\4.0
C'est ici que figure de nombreuses options internes au moteur Jet, comme par exemple le chemin du fichier de groupe de travail utilisé.

Bien qu'importante au moteur de base de données, cette propriété représente trés peu d'intérêt pour le développeur hormis de localiser le chemin où est stocké le fichier de groupe de travail.

3-1-2-7 - Properties

Type : Collection

Collection regroupant l'ensemble des propriétés (Property) de l'objet DBEngine.

Pour plus d'informations sur la collection Properties, je vous renvoie vers la section 4.2 Les propriétés spécifiques.

3-1-2-8 - SystemDB

Type : String

Il s'agit du chemin d'accès au fichier mdw (fichier de groupe de travail) à utiliser. Le fichier utilisé par défaut est celui contenu dans l'entrée du fichier ini ou de la base de registre spécifiée dans la propriété IniPath.

3-1-2-9 - Version

Lecture seule.

Type : String

La propriété Version correspond à la version du moteur Jet. Par exemple : 3.6.

3-1-2-10 - Workspaces

Type : Collection

Collection regroupant l'ensemble des espaces de travail (Worspaces(0) étant l'espace de travail par défaut).

Pour de plus amples informations, veuillez consulter le chapitre suivant : L'objet Workspace.

3-1-3 - Liste des méthodes

Je vous propose la liste des méthodes applicables aux objets de la classe DBEngine.

3-1-3-1 - BeginTrans

La méthode BeginTrans commence une transaction.

Exemple :

DBEngine.BeginTrans

3-1-3-2 - CommitTrans

La méthode CommitTrans stoppe la transaction tout en enregistrant les données.

Exemple :

DBEngine.CommitTrans

3-1-3-3 - CompactDatabase

La méthode CompactDatabase copie et compacte une base de données. Notons que la base de données doit être fermée pour réaliser cette opération.

Syntaxe :

DBEngine.CompactDatabase olddb, newdb, [locale], [options], [password]

olddb correspond au fichier source et newdb au fichier de destination (différent de olddb). Les autres options concernent essentiellement la langue, la version et le codage utilisé. Il s'agit de constantes disponibles dans l'aide Access.

Exemple :

DBEngine.CompactDatabase "c:\bd1.mdb", "c:\bd2.mdb"

3-1-3-4 - CreateDatabase

La méthode CreateDatabase permet de créer une nouvelle base de données. Elle renvoie un objet de type DAO.Database.

Syntaxe :

Set database = DBEngine.CreateDatabase (name, locale, [options])

L'argument name correspond au nom complet de la base de données.
locale est une constante représentant l'ordre de tri à appliquer (dbLangGeneral pour la France). Le dernier argument est facultatif et permet de spécifier le codage et la version de la base de données.

Exemple :

Set db = DBEngine.CreateDatabase("c:\mabase.mdb", dbLangGeneral)

3-1-3-5 - CreateWorkspace

Cette méthode permet de créer un nouvel objet WorkSpace (Espace de travail) et retourne l'objet créé.

Syntaxe :

Set workspace = DBEngine.CreateWorkspace(name, user, password, [type])

Name correspond au nom de l'espace de travail. Il permettra de l'identifier de manière unique dans la collection Workspaces.
User correspond au nom de l'utilisateur dans cet espace et password à son mot de passe (14 caractères au maximum). Ce couple d'authentification doit obligatoirement figurer dans le fichier mdw spécifié dans la propriété SystemDB, sans quoi une erreur sera levée par le moteur de base de données.
Le dernier argument est facultatif et correspond au type d'espace à créer. S'il n'est pas mentionné, ce sera le type figurant dans la propriété DefaultType qui sera utilisé.

Exemple :

Set Wks = DBEngine.CreateWorkspace("MonEspace", "Toto", "mdp#@#!mJ")

3-1-3-6 - Idle

La méthode Idle donne la possibilité au moteur JET de traiter ses tâches en attente. Notons que cette méthode possède un argument facultatif. Si ce dernier est égal à dbRefreshCache, la mémoire est réactualisée avec uniquement les données les plus récentes en provenance du fichier de base de données.

Exemple :

DBEngine.Idle

3-1-3-7 - OpenDatabase

Comme son nom l'indique, cette méthode ouvre une base de données. Elle renvoie un objet de type DAO.Database.

Syntaxe :

Set database = workspace.OpenDatabase (dbname, options, read-only, connect)

Dbname correspond au chemin d'accès de la base de données à ouvrir. Cet argument peut aussi être le nom d'une source ODBC. Si cette chaîne est nulle, et que la variable connect est égale à "ODBC;", une boite de dialogue de sélection de source de données est affichée.

L'argument option permet de spécifier si la base de données doit être ouverte en mode exclusif (True) ou pas (False). De plus l'argument read-only ouvre la base de données en lecture seule lorsqu'il est égal à True.

Enfin, l'argument connect est utilisé à la fois pour spécifier le type de base de données et le mot de passe système à utiliser pour ouvrir le fichier.

L'objet Database créé est ajouté automatiquement à l'espace de travail Workspaces(0).

Exemple :

Set db = DBEngine.OpenDatabase("c:\bd1.mdb", False, False, _
"MS Access;PWD=mdp#@#!e)

3-1-3-8 - RepairDatabase

La méthode RepairDatabase répare la base de données. Notons qu'elle n'est plus utilisée et est réservée pour assurer la compatibilité avec les anciennes versions.

Il est recommandé d'utiliser la méthode CompactDatabase en remplacement.

3-1-3-9 - Rollback

Cette méthode met fin à une transaction démarrée avec BeginTrans.

Exemple :

DBEngine.RollBack

3-2 - L'objet Workspace

3-2-1 - Généralités

Deux types d'espaces de travail sont à distinguer :

Espace de travail Jet : Zone de travail utilisant le moteur de base de données Microsoft Jet pour accéder à une source de données. Cette source de données peut prendre la forme d'un fichier de base de données Microsoft Jet (.mdb), ODBC, Paradox ou ISAM.

Espace de travail ODBC Direct : Il s'agit d'une technique d'accés aux données à une source ODBC sans passer par le moteur de base de données Jet.

Seul l'espace de travail Jet sera abordé ici.

Un objet Workspace représente un espace de travail au sein du moteur de base de données (DBEngine). Il s'agit en fait d'une session du DBEngine dédiée à un utilisateur donné. Hormis le cas où vous voulez gérer vous-même l'ouverture de la base de données dans un environnement sécurisé, l'utilisation de l'objet Workspace sous Access a peu d'intérêt. En effet, l'objet Workspaces(0) du DBEngine est l'espace de travail par défaut. Il est instancié automatiquement par Access lors d'un appel à un objet DAO. Ainsi, en général, vous utiliserez une référence implicite à celui ci, notamment lorsque que vous utiliserez les méthodes CodeDB ou CurrentDB de l'objet Access.Application.

Toutefois, tout comme l'objet DBEngine, le Workspace est capable d'exécuter des méthodes de transaction, et permet en plus de paramétrer la gestion des curseurs du moteur Jet (Recordset). Son utilisation peut devenir alors primordiale lorsque l'on souhaite paramétrer d'avantage l'accès aux données.

Comme il a été précisé dans le chapitre précédent, c'est à partir de l'objet DBEngine qu'est créé chaque objet Workspace à l'aide de la méthode CreateWorkspace.

La méthode CreateWorkspace demande un identifiant unique pour l'objet créé. De plus, la création de tels objets est très rare dans le temps. Aussi, il est possible d'utiliser une variable qui contiendra la date de création de l'objet comme nom de l'objet Workspace à instancier.

Voici un exemple de création d'un objet Workspace :

Dim oWks As DAO.Workspace
Set oWks = DBEngine.CreateWorkspace(Format(Now(), _
"yyyymmddhhnnss"), "Utilisateur1", "mpd#ç#", dbUseJet)

3-2-2 - Liste des propriétés

Vous trouverez ci-dessous la liste des propriétés applicables à un objet de la classe Workspace.

3-2-2-1 - Databases

Type : Collection

Collection regroupant l'ensemble des objets Database ouverts dans l'objet Workspace correspondant.

3-2-2-2 - IsolateODBCTrans

Type : Boolean

Si cette propriété est égale à False (valeur par défaut), il est possible d'effectuer plusieurs transactions simultanées sur la même connexion ODBC. Toutefois, les bases de données SQL Server n'acceptent pas ce mode de fonctionnement, aussi dans le cas de connexion ODBC avec ce type de base de base de données, il vous faudra fixer cette propriété à True.

3-2-2-3 - Name

Lecture seule.

Type : String

La propriété Name correspond au nom de l'objet Workspace concerné. Ce nom est unique au sein de la collection DBEngine.Workspaces.

3-2-2-4 - Properties

Comme tout autre objet DAO, l'objet Workspace possède cette collection qui regroupe l'ensemble des propriétés (Property) de cet objet.

De plus amples informations sur la collection Properties sont disponibles dans le chapitre Les propriétés spécifiques.

3-2-2-5 - Type

Lecture seule.

Type : Long

Il s'agit du type de l'espace de travail. Sa valeur est celle que vous avez spécifié à la méthode CreateWorkspace du DBEngine. Si vous n'avez pas mentionné cette valeur lors de la création de l'espace de travail, il s'agit de la valeur de la propriété DefaultType du moteur de base de données. L'objet Workspaces(0) étant instancié automatiquement par Access lors d'un appel à un objet DAO, la propriété Workspaces(0).Type est donc égale à dbUseJet.
L'autre valeur disponible est dbUseODBC.

3-2-3 - Liste des méthodes

Voici la liste des méthodes proposées par la classe Workspace. Bon nombre de ces méthodes sont communes à la classe DBEngine.

3-2-3-1 - BeginTrans

La méthode BeginTrans commence une transaction.

Exemple :

DBEngine.Workspaces(0).BeginTrans

3-2-3-2 - Close

La méthode Close ferme l'espace de travail correspondant. Notez que si vous fermez un objet Workspace, ses transactions en attentes sont détruite. De même si cet objet Workspace possède des objets Database ou Connection, ces objets sont aussi fermés, ce qui a pour effet de fermer leurs objets recordsets associés.

La fermeture d'un objet Workspace doit donc être une action réfléchie car elle peut entrainer la perte irrémédiable de données.

Exemple :

DBEngine.Workspaces(0).BeginTrans

3-2-3-3 - CommitTrans

Cette méthode stoppe une transaction démarée avec BeginTrans tout en enregistrant les données.

Exemple :

DBEngine.Workspaces(0).CommitTrans

3-2-3-4 - CreateDatabase

La méthode CreateDatabase permet de créer une nouvelle base de données. Elle renvoie un objet de type DAO.Database.

Syntaxe :

Set database = Workspace.CreateDatabase (name, locale, [options])

L'argument name correspond au nom complet de la base de données.
locale est une constante représentant le tri à appliquer (dbLangGeneral pour la France). Le dernier argument est facultatif et permet de spécifier le codage et la version de la base de données.

Exemple :

Set db = DBEngine.Workspaces(0).CreateDatabase("c:\mabase.mdb", dbLangGeneral)

3-2-3-5 - OpenDatabase

Comme son nom l'indique, la méthode OpenDatabase ouvre une base de données. Elle renvoie un objet de type DAO.Database.

Syntaxe :

Set database = workspace.OpenDatabase (dbname, options, read-only, connect)

Dbname correspond au chemin d'accès de la base de données à ouvrir. Cet argument peut aussi être le nom d'une source ODBC. Si cette chaîne est nulle, et que la variable connect vaut "ODBC;", une boite de dialogue de sélection de source de données est affichée.

L'argument option permet de spécifier si la base de données doit être ouverte en mode exclusif (True) ou pas (False). De plus l'argument read-only ouvre la base de données en lecture seule lorsqu'il vaut True.

Enfin, l'argument connect est utilisé à la fois pour spécifier le type de base de données et le mot de passe pour ouvrir le fichier.

L'objet database créé est automatiquement ajouté à la collection Databases de l'objet Workspace aprés sa création.

Exemple :

Set db = DBEngine.Workspaces(0).OpenDatabase("c:\bd1.mdb", False, False, _
"MS Access;PWD=mdp#@#!e")

3-2-3-6 - Rollback

La méthode Rollback met fin à une transaction démarrée avec BeginTrans.

Exemple :

DBEngine.Workspaces(0).RollBack

3-2-4 - Accéder à un groupe de travail spécifique

Comme il a été précisé plus haut, l'objet Workspace prend de l'importance lorsqu'il s'agit d'ouvrir une base de données sécurisée. En effet, lorsque que vous ouvrez un fichier mdb avec Access, vous êtes authentifié au sein d'un fichier de groupe de travail. Cela peut être le fichier System.mdw par défaut si vous n'avez pas implémenté de gestion de sécurité ou bien un fichier de votre création rassemblant les informations nécessaires à la protection de votre base de données. Or, il se peut que vous ayez besoin d'accéder à une autre base de données via DAO nécessitant d'utiliser un autre fichier mdw pour se connecter. Dans ce cas, il vous faut instancier un autre objet de type DAO.DBEngine et spécifier le chemin du fichier de groupe de travail à utiliser dans la propriété DBEngine.SystemDB.

Toutefois, cette méthode possède un inconvénient majeur. En effet, si vous essayez d'instancier un nouvel objet DBEngine alors que vous avez déjà utilisé des méthodes DAO auparavant dans votre code, il vous sera impossible de modifier la propriété SystemDB du nouvel objet DBEngine créé. Celle-ci conservera pour valeur celle de Application.DBEngine.SystemDB bien qu'aucune erreur ne soit levée lorsque vous tenterez de la modifier.

Il est donc impératif que l'instanciation de nouveaux objets DBEngine ait lieu avant tout autre appel DAO y compris les méthodes CodeDb et CurrentDb.

Je vous propose la création d'une interface permettant d'ouvrir une base de données Access en spécifiant le fichier mdw à utiliser.

Soit le formulaire suivant :

Il est composé de haut en bas :

- Une zone de texte TFichier

- Une liste modifiable ListeSecu

- Une zone de texte TAdmin

- Une zone de texte TUser

- Une zone de texte TMDP

Voici le code correspondant :

Code du bouton Valider :

Private Sub Commande10_Click()
'Ouvre le fichier avec la sécurité choisie
On Error GoTo err
Dim strfichier As String
Dim oVDb As DAO.Database
Dim chaine As String
Dim oVWk As DAO.Workspace
Dim oDbe As DBEngine
Dim strFichierMDW As String
If Len(TFichier) <> 0 Then

strfichier = TFichier
'prépare l'espace de travail
If ListeSecu.ListIndex = 0 Or ListeSecu.ListIndex = 2 Then
Set oVWk = Workspaces(0)
Else
strFichierMDW = OuvrirUnFichier(Me.HWnd, _
"Selectionner un fichier de groupe de travail", 1, _
"Fichier mdw", "mdw")
If strFichierMDW = "" Then
Exit Sub
Else
Set oDbe = New DBEngine
oDbe.SystemDB = strFichierMDW
Set oVWk = oDbe.CreateWorkspace(Format(Now(), _
"yyyymmddhhnnss"), TUtilisateur, TMDP, dbUseJet)
End If
End If
'Ouvre la base de données
If ListeSecu.ListIndex = 2 Or ListeSecu.ListIndex = 3 Then
Set oVDb = oVWk.OpenDatabase(strfichier, False, False, _
"MS Access;PWD=" & TAdmin)
Else
Set oVDb = oVWk.OpenDatabase(strfichier)
End If
Else
MsgBox "Vous devez sélectionner un fichier", _
vbExclamation, "Saisie du fichier"
End If
Exit Sub
err:
MsgBox "Impossible de se connecter à la base de données. " & _
"Vérifier le chemin d'accès et les informations " & _
"d'authentification", vbCritical, "Erreur"
End Sub

Code d'ouverture du formulaire :

Private Sub Form_Load()
'Vide les controles
Dim ctlT As Control
For Each ctlT In Me.Controls
If TypeOf ctlT Is TextBox Then
ctlT.Value = ""
If  ctlT.Name <> "TFichier" Then ctlT.Enabled = False
End If
Next ctlT
ListeSecu = "Aucune"
End Sub

Code du bouton parcourir

Private Sub Commande3_Click()
Dim strChemin As String
strChemin = OuvrirUnFichier(Me.Hwnd, _
"Selectionner une base de données Access", _
1, "Fichiers Access", "mdb")
If  strChemin <> "" Then
Me.TFichier = strChemin
End If
End Sub

La fonction OuvrirUnFichier est disponible dans la FAQ Access. Elle permet d'afficher une boîte de dialogue de sélection de fichier.

La base de données ainsi ouverte est disponible via l'objet : VDB de la procédure du bouton Valider.

Cette interface permet à la fois de s'authentifier au sein d'un fichier de groupe de travail et de saisir le mot de passe système pour l'ouverture de l'objet Database.

Le choix du fichier de groupe de travail se réalise ici :

Set oDbe = New DBEngine
oDbe.SystemDB = strFichierMDW
Set VWK = oDbe.CreateWorkspace(Format(Now(), _
"yyyymmddhhnnss"), TUtilisateur, TMDP, dbUseJet)

La première ligne permet d'instancier le nouveau moteur de base de données auquel nous spécifions ensuite le fichier mdw à ouvrir. Puis nous créons enfin le l'espace de travail à l'aide de la méthode CreateWorkspace.

Une des raisons majeures pour lesquelles la création de l'espace de travail lève une erreur est que le couple utilisateur - mot de passe est invalide dans le fichier mdw sélectionné. Il se peut aussi que l'affectation de la propriété SystemDB ait échouée, ce qui signifie que le code de votre projet utilise des méthodes DAO avant ce bloc d'instructions. Un moyen simple de le vérifier :

MsgBox oDbe.SystemDB
oDbe.SystemDB = FichierMDW
MsgBox oDbe.SystemDB

Si les deux MsgBox affichent le même résultat, cela indique que votre code utilise des instructions DAO avant cette procédure.

3-3 - L'objet Database

3-3-1 - Généralités

Comme vous avez pu le remarquer dans la fenêtre de base de données de l'application Access, un fichier mdb peut être décomposé en deux parties :

- La partie applicative. Elle regroupe à la fois les formulaires, les états, les modules et les macros.

- La partie données. Cette partie se retrouve dans l'ensemble des SGBD (Système de Gestion de Base de Données). Il s'agit des tables et des requêtes. Access étant un SGBDR (SGBD Relationnel), cette partie regroupe aussi l'ensemble des relations entre les différentes tables.

Le modèle objet DAO donne accès à la partie données via son objet Database. Cet objet est à la racine du DDL (Langage de définition de données) et du DML (Langage de manipulation de données) sous DAO. C'est à partir de ce même objet Database que l'on va créer les tables, les requêtes, les relations et manipuler les données (Insert, Update, Delete).

Comme il a été écrit plus haut, un objet database peut être instancié depuis un moteur de base de données (DBEngine) ou depuis un espace de travail (Workspace) à l'aide des méthodes CreateDatabase et OpenDatabase. Ceci peut être fait de manière explicite :

Dim oDb As DAO.Database
Set oDb=DBEngine.CreateDatabase (…)

Ou de manière implicite :

Dim oDb As DAO.Database
Set oDb=CreateDatabase(…)

Toutefois, dans la majorité des cas, vous souhaitez utiliser la base de données courante ouverte dans Access. Il vous suffit alors d'utiliser les méthodes Application.CurrentDb ou Application.CodeDb.

3-3-1-1 - La méthode CurrentDb

Cette méthode fournie par l'objet Access.Application retourne une variable de type Database correspondant à la base de données actuellement ouverte dans le logiciel Microsoft Access. La méthode Currentdb crée une nouvelle instance de la base de données à chaque appel. Aussi, vous devez récupérer son résultat dans une variable objet de type Database pour pouvoir l'exploiter.

Voici ce qu'il ne faut pas utiliser :

Dim Tbl As DAO.TableDef, Tbl2 As DAO.TableDef
Set Tbl = CurrentDb.TableDefs("Table1")
Set Tbl2 = CurrentDb.TableDefs("Table2")

En effet, ce code fait un double appel à Currentdb ce qui provoque une double instanciation de la base de données courante.

Dim Tbl As DAO.TableDef, Tbl2 As DAO.TableDef
Dim Db as DAO.Database
Set Db=CurrentDb
Set Tbl = Db.TableDefs("Table1")
Set Tbl2 = Db.TableDefs("Table2")

Ici, une seule instance de l'objet database est utilisée.

La propriété DBEngine.Workspaces(0).Databases(0) représente aussi la base de données ouverte. Toutefois, cette méthode est déconseillée car elle ne crée pas une nouvelle instance de l'objet Database. Au contraire, son résultat peut être considéré comme un pointeur vers la base de données. Aussi, dans un environnement multi-utilisateurs, ceci peut engendrer des conflits d'accès aux données. Privilégiez donc la méthode CurrentDb.

3-3-1-2 - La méthode CodeDb

Contrairement à la méthode CurrentDb qui renvoie la base de données active, cette méthode retourne un objet Database correspondant à la base de données qui contient le code en cours d'exécution .
CodeDb est à utiliser lors de la création de compléments ou de base de données bibliothèques. En effet la base Add-in ne sera pas la base active. La méthode CurrentDb ne retournera donc pas le bon objet Database. Tout comme CurrentDb, Codedb retourne une nouvelle instance de l'objet Database. Vous devez donc récupérer son résultat dans un objet Database pour pouvoir l'exploiter.

Dim Tbl As DAO.TableDef, Tbl2 As DAO.TableDef
Dim Db as DAO.Database
Set Db=CodeDb
Set Tbl = Db.TableDefs("Table1")
Set Tbl2 = Db.TableDefs("Table2")

3-3-2 - Liste des propriétés

3-3-2-1 - CollatingOrder

Type : Long

Il s'agit de la méthode utilisée par le moteur pour comparer les données de type texte.

Les valeurs possibles sont :

Constante

Signification

dbSortGeneral

Général (Français, anglais ...)

dbSortArabic

Arabe

dbSortChineseSimplified

Chinois simplifié

dbSortChineseTraditional

Chinois traditionnel

dbSortCyrillic

Russe

dbSortCzech

Tchèque

dbSortDutch

Néerlandais

dbSortGreek

Grec

dbSortHebrew

Hébreu

dbSortHungarian

Hongrois

dbSortIcelandic

Islandais

dbSortJapanese

Japonais

dbSortKorean

Coréen

dbSortNeutral

Neutre

dbSortNorwDan

Norvégien et danois

dbSortPDXIntl

Paradox International

dbSortPDXNor

Paradox norvégien ou danois

dbSortPDXSwe

Paradox suédois ou finnois

dbSortPolish

Polonais

dbSortSlovenian

Slovène

dbSortSpanish

Espagnol

dbSortSwedFin

Suédois ou finnois

dbSortThai

Thaï

dbSortTurkish

Turc

dbSortUndefined

Indéfini

3-3-2-2 - Connect

Lecture Seule.

Type : String

La propriété Connect représente la chaîne de connexion utilisée à l'ouverture de l'objet Database. Lorsque que vous utilisez cette propriété sur une base au format Access, cette propriété est égale à "".

3-3-2-3 - Containers

Type : Collection

Cette collection regroupe l'ensemble des objets de type container contenu dans la base de données. Il s'agit de l'ensemble des objets enregistrés dans la base de données. Vous y touverez par exemple des informations sur les formulaires, les états ...

Cette propriété vous est founie à titre d'information, en effet, un tutoriel entier pourrait lui être consacré.

3-3-2-4 - Name

Lecture Seule.

Type : String

La propriété Name d'un objet Database retourne le nom de la base de données. Pour une base de données Access, il s'agit du nom du fichier mdb ainsi que le chemin d'accès complet vers ce fichier.

3-3-2-5 - Properties

Type : Collection

Collection regroupant l'ensemble des objets Property de l'objet Database.

3-3-2-6 - QueryDefs

Type : Collection

Cette collection regroupe l'ensemble des requêtes enregistrées dans la base de données.

Cette partie sera largement détaillée dans la section 4.7 L'objet QueryDef.

3-3-2-7 - RecordsAffected

Lecture Seule.

Type : Long

La propriété RecordsAffected retourne le nombre d'enregistrements qui ont été affectés par le dernier ordre SQL de la méthode Execute. Cela permet de connaitre, par exemple, le nombre de lignes supprimées lors d'une requête Delete.

Exemple d'utilisation :

Dim Requete As String
Dim DB As DAO.Database
Requete = "DELETE FROM MaTable WHERE ChampID>20"
Set DB = CurrentDb
DB.Execute Requete
MsgBox DB.RecordsAffected

3-3-2-8 - Recordsets

Lecture Seule.

Type : Collection

Cette collection regroupe l'ensemble des objets recordset ouverts dans la base de données.

Cette partie sera largement détaillée dans le chapitre 5 Accès aux données.

3-3-2-9 - Relations

Type : Collection

La propriété Relations est une collection regroupant l'ensemble des relations présentes dans la base de données. Cette collection n'est utile que pour les SGBDR.

Cette partie sera largement détaillée dans la section 4.6 L'objet Relation.

3-3-2-10 - TableDefs

Type : Collection

Cette collection regroupe l'ensemble des tables enregistrées dans la base de données. Dans le cas d'une base de données incluant des tables liées, il existe aussi un objet TableDef pour chaque table attachée.

Cette partie sera largement détaillée dans la section : 4.3 L'objet TableDef.

3-3-2-11 - Transactions

Lecture Seule.

Type : Boolean

La propriété Transactions d'un objet Database indique si l'objet database supporte les transactions. Si oui, la valeur de la propriété est égale à True.
Dans le cas d'une base de données Access, cette valeur est fixée à True et les transactions sont disponibles via les objets Recordset Dynaset et Table.

3-3-2-12 - Updatable

Lecture Seule.

Type : Boolean

Si cette propriété est égale à False, la base de données est protégée en écriture et vous ne pouvez modifier ni les données, ni la structure.

3-3-2-13 - Version

Lecture Seule.

Type : String

Cette propriété retourne la version du moteur Jet utilisé pour créer la base de données. Dans le cas, d'une base de données Access au format 2000 ou ultérieur, cette propriété est égale à 4.0.

3-3-3 - Liste des méthodes

3-3-3-1 - Close

La méthode Close ferme la base de données. Toutefois, cela ne libère pas la mémoire alloué à l'objet database. Pour libérer la mémoire, vous devez affecter Nothing à la variable.

3-3-3-2 - CreateProperty

La méthode CreateProperty crée et retourne un objet Property.

Syntaxe :

Set property = object.CreateProperty (name, type, value, DDL)

Nous reviendrons plus en détails sur les objets property dans le chapitre suivant.

3-3-3-3 - CreateQueryDef

La méthode CreateQueryDef crée une nouvelle requête et retourne l'objet QueryDef correspondant. L'objet créé est automatiquement ajouté à la collection Database.QueryDefs.

Syntaxe :

Set querydef = Database.CreateQueryDef (name, sqltext)

L'argument name correspond au nom de la requête à créer. Celui ci doit être unique au sein de la collection QueryDefs. En affectant une chaine vide ("") à ce paramètre, vous créez un objet QueryDef temporaire qui ne sera pas ajouté à la collection QueryDefs. Dans ce cas, l'objet sera détruit à la fin de la procédure.

L'argument SQL est une chaîne de caractères contenant l'instruction SQL de la requête à créer. Il peut s'agir de requête de sélection, de mise à jour, de supression, etc ...

Le fonctionnement de l'objet QueryDef est illustré dans le chapitre intitulé : L'objet QueryDef

3-3-3-4 - CreateRelation

La méthode CreateRelation crée et retourne un objet Relation.

Syntaxe :

Set relation = database.CreateRelation (name, table, foreigntable, attributes)

Nous reviendrons plus en détails sur les objets Relation dans le chapitre suivant.

3-3-3-5 - CreateTableDef

La méthode CreateTableDef crée et retourne un objet Tabledef. A ce stade, l'objet est seulement créé et n'est pas encore intégré à la base de données. Pour l'ajouter aux autres tables, vous devrez invoquer la méthode Append de la collection TableDefs.

Syntaxe :

Set tabledef = database.CreateTableDef (name, attributes, source, connect)

La création de table sera abordée en détails dans le chapitre suivant à la section 4.3 L'objet TableDef

3-3-3-6 - Execute

Cette méthode execute un ordre SQL. Cette ordre SQL doit être une requête action (Insert, Update, Delete). Les requêtes de sélection sont déléguées aux objets Recordset. Une fois l'ordre SQL exécuté, il est possible de connaitre le nombre d'enregistrements qui ont été affectés par cet ordre grâce à la propriété RecordsAffected.

Exemple :

Dim Db as DAO.Database
Set Db=CurrentDb
Db.Execute ("DELETE FROM MaTable")

3-3-3-7 - NewPassword

La méthode NewPassword permet de modifier le mot de passe système de la base de données.

Ne pas confondre le mot de passe système et le mot de passe utilisateur utilisé dans un groupe de travail. Le mot de passe système est celui définit dans le menu Outils/Sécurité/Définir le mot de passe de la base de données.

Exemple :

Dim Db as DAO.Database
Set Db=CurrentDb
Db.NewPassword "mdpancien","mdpnouveau"

3-3-3-8 - OpenRecordset

La méthode OpenRecordset ouvre et retourne un objet Recordset (Curseur) permettant d'accéder aux données.
L'objet ainsi créé est automatiquement ajouté à la collection Recordsets.

Vous retrouverez cette méthode dans le chapitre 5 Accès aux données.

4 - DAO et la structure d'une base de données

4-1 - Généralités

Nous abordons là un point fort de DAO à savoir la définition des données (DDL). En effet, l'objet Database donne accès à l'ensemble des tables, des requêtes et des relations d'une base de données Access. Non seulement il est possible de consulter les différents objets mais il est aussi possible de les modifier, d'en ajouter et d'en supprimer. Vous pouvez donc, via votre code VBA, travailler sur la structure de votre fichier comme vous le feriez en mode création dans l'application Access. L'intérêt est bien entendu de pouvoir modifier cette structure sans aucune intervention de l'utilisateur. (Laisser l'utilisateur agir sur les tables directement constitue un réel danger pour votre application). Pour cela, les autres SGBD utilisent généralement le langage SQL (avec des instructions Create, Alter, Drop …). Access ne dispose pas de tant de possibilités avec son langage SQL. Le recours à la programmation VBA devient donc impératif pour réaliser certaines opérations. Nous allons donc voir plus loin dans ce chapitre comment travailler sur les tables, les requêtes et les relations. Mais, dans un premier temps, nous allons aborder le thème des propriétés spécifiques.

4-2 - Les propriétés spécifiques

4-2-1 - Définitions

DAO est un modèle objet. Aussi chaque objet qui le compose possède une liste de propriétés dont chacune d'elles correspond à un objet Property. Vous vous demandez alors quel est l'intérêt de la collection Properties puisque ces propriétés sont disponibles sous VBA avec la syntaxe : Objet.Propriété. Certes Visual Basic liste certaines propriétés mais il ne les propose pas toutes. Ainsi par exemple, les objets TableDef possèdent une propriété Description qui correspond à la description de la table. Cette propriété n'est pas listée dans le récapitulatif des propriétés des objets TableDef, le seul moyen de l'atteindre est d'utiliser la collection TableDef.Properties.

Pourquoi certaines propriétés ne figurent que dans la collection properties ?

Tout d'abord, bon nombre de propriétés de la collection Properties ne sont pas créées jusqu'à ce qu'une valeur ne leur soit affectée. Ainsi, la propriété description de l'objet TableDef n'existe pas si vous n'avez pas encore saisi la description de la table sous Access.

De plus vous pouvez créer vos propres propriétés et les ajouter à la collection Properties de l'objet de votre choix.
Il devient donc impossible de réaliser une liste exhaustive de l'ensemble des propriétés d'un objet DAO.

4-2-2 - Liste des propriétés d'un objet Property

Chaque objet Property possède lui aussi un ensemble de propriétés.

4-2-2-1 - Inherited

Lecture seule.

Lorsque cette propriété est égale à True, cela signifie que la propriété ne fait pas partie de l'objet même mais qu'elle est héritée d'un autre objet.
Imaginons un objet QueryDef Q1 auquel nous ajoutons une propriété personalisée P1. P1 a été créée pour Q1 donc, la propriété P1.Inherited est égale à False. Si par la suite nous ouvrons un recordset R1 sur Q1, la propriété P1 se retrouvera dans la collection Properties de R1. P1 sera alors héritée et P1.Inherited sera égale à True.

Dans ce cas, ces deux expressions seront vérifiées :

Q1.Properties("P1").Inherited=False

Et :

R1.Properties("P1").Inherited=True

4-2-2-2 - Name

Cette propriété correspond au nom de la propriété. Celui-ci doit être unique au sein de la collection Properties de l'objet concerné, sans quoi une erreur sera levée lorsque vous tenterez d'ajouter le nouvel objet Property à la collection Properties.

Utilisez des noms précis et en relation avec ce que la propriété modélise. De même éviter d'utiliser des mots réservés par Visual Basic. Ainsi, si la propriété représente une date de vérification, nommez la DateVerification et non pas simplement Date.

4-2-2-3 - Type

Il s'agit du type de la propriété. Sa valeur doit être une des constantes suivantes :

Constante

Valeur

Type

dbBigInt

16

Numérique (haute précision)

dbBinary

9

Binaire de longueur fixe (255 octets maxi)

dbBoolean

1

Booléen

dbByte

2

Octet

dbChar

18

Chaîne de caractère de longueur fixe

dbCurrency

5

Monétaire

dbDate

8

Date/Heure

dbDecimal

20

Décimal

dbDouble

7

Double

dbFloat

21

Réel à virgule flottante

dbGUID

15

Identifiant GUID

dbInteger

3

Entier

dbLong

4

Entier long

dbLongBinary

11

Binaire à longueur variable. (OLE)

dbMemo

12

Mémo

dbNumeric

19

Numérique

dbSingle

6

Réel Simple

dbText

10

Texte à longueur fixe

dbTime

22

Heure

dbTimeStamp

23

TimeStamp

dbVarBinary

17

Binaire à longueur variable (255 octets maxi)

4-2-2-4 - Value

Cette propriété correspond à la valeur de l'objet Property. Cette valeur doit être compatible avec le type spécifié dans la propriété Type.

4-2-3 - Accéder à une propriété

La collection Properties fonctionne comme toute autre collection DAO. Toutefois, ne connaissant pas le contenu de la collection, il paraît difficile d'accéder à un élément via son index dans la collection. Il nous faut donc spécifier le nom de l'élément à rechercher. Il se pose alors un autre problème qui est que nous ne savons pas si l'objet Property à rechercher existe. En effet, comme nous l'avons vu, par exemple plus haut avec la propriété description des objets Tabledef, celle-ci n'existe que si elle a été initialisée auparavant. Dés lors, nous devons vérifier l'existence de la propriété avant d'y accéder.

Deux méthodes peuvent alors être utilisées. La première consiste à parcourir chacun des objets Property de la collection est de retourner un booléen si l'élément a été trouvé.

Public Function ExistProperty(ColTProperties As DAO.Properties, _
strTNom As String) As Boolean
Dim oTmpPrp As DAO.Property
For Each oTmpPrp In ColTProperties
If oTmpPrp.Name = strTNom Then
ExistProperty = True
Exit For
End If
Next oTmpPrp
End Function

Exemple d'utilisation :

Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
Set oTbl = oDb.TableDefs("Commande")
MsgBox ExistProperty(oTbl.Properties, "description")

La seconde méthode consiste à tenter d'accéder à la propriété via son nom et de traiter l'erreur si celle-ci n'existe pas.

Public Function ExistProperty(ColTProperties As DAO.Properties, _
strTNom As String) As Boolean
On Error GoTo err
Dim oTmpPrp As DAO.Property
Set oTmpPrp = ColTProperties(strTNom)
ExistProperty = True
err:
End Function

L'utilisation de la fonction reste la même que celle de la précédente. Toutefois, la seconde méthode est plus rapide du fait qu'elle n'utilise pas de boucle.

Dans le cas où vous n'utiliseriez pas une de ses fonctions et que la propriété n'est pas trouvée dans la collection Properties, l'erreur d'exécution 3270 (Propriété non trouvée) sera levée.

Une fois la propriété trouvée, il est possible de connaître sa valeur à l'aide de la propriété value.

Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
Set oTbl = oDb.TableDefs("Commande")
If ExistProperty(oTbl.Properties, "description") Then
MsgBox oTbl.Properties("description").Value
Else
MsgBox "Cette propriété n'existe pas"
End If
oDb.Close
Set oDb=Nothing
Set oTbl=Nothing

4-2-4 - Modifier la valeur d'une propriété

Pour modifier la valeur d'un objet Property, il faut tout d'abord que celui ci existe. Nous pouvons donc réutiliser une des fonctions citées plus haut. Ensuite, il suffit de modifier la valeur de l'objet Property en utilisant la propriété Value. Cependant, certaines propriétés sont en lecture seule. Aussi, l'implémentation d'une gestion d'erreur devient impérative.

Voici un exemple de fonction utilisable pour modifier une propriété spécifique d'un objet DAO :

Public Function ModifProperty(colTProperties As DAO.Properties, _
strTNom As String, strTValeur As Variant) As Boolean
On Error GoTo err
Dim oTmpPrp As DAO.Property
'Recherche l'élément
Set oTmpPrp = colTProperties(strTNom)
'Modifie la valeur
oTmpPrp.Value = strTValeur
'Rafraichit la collection
colTProperties.Refresh
'L'opération est terminée, renvoyer True
ModifProperty = True
Exit Function
'Gestion des erreurs
err:
Select Case err.Number
Case 3270
MsgBox "Propriété non trouvée"
Case 3421
MsgBox "Type de propriété incompatible"
Case Else
MsgBox "La propriété est en lecture seule"
End Select
End Function

Utilisation :

Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
Set oTbl = oDb.TableDefs("Commande")
ModifProperty oTbl.Properties, "description", "essai"

Quelques remarques sur cette fonction :

TValeur correspond à la nouvelle valeur de la propriété. Le type de cet argument est Variant, pour s'adapter à l'ensemble des types possibles. Toutefois, si vous ne souhaitez modifier des propriétés exclusivement de type String, vous pouvez remplacer le type Variant par String.

La méthode Refresh appliquée à la collection Properties permet de mettre à jour immédiatement la propriété. Si cette méthode n'est pas employée, les modifications ne seront effectives qu'après avoir redémarré votre application.

La fonction renvoie false en cas d'échec de la modification de la propriété.

Il est inutile d'utiliser cette fonction pour les propriétés non spécifiques. En effet, les propriétés proposées par l'explorateur d'objets (F2) sont des propriétés intégrées que vous pouvez modifier avec la syntaxe habituelle Objet.Propriété.

Exemple :

Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
Set oTbl = oDb.TableDefs("Commande")
oTbl.name= "essai"

4-2-5 - Création d'une nouvelle propriété

Pour créer une nouvelle propriété, vous devez d'abord vérifier que celle-ci n'existe pas. Ensuite, il suffit d'appliquer la méthode CreateProperty de l'objet concerné pour instancier un nouvel objet Property. A ce stade, la propriété est seulement créée, elle n'est pas encore ajoutée à la liste des propriétés de l'objet. Pour l'ajouter, vous devez utilisez la méthode Append de la collection Properties.

Voici un exemple qui ajoute une propriété nommée "test" de type Integer à la table commande.

Sub ajout()
Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Dim oPrp As DAO.Property
Set oDb = CurrentDb
Set oTbl = oDb.TableDefs("Commande")
'verifie que la propriété n'existe pas
If Not ExistProperty(oTbl.Properties, "test") Then
'Crée la nouvelle propriété
Set oPrp = oTbl.CreateProperty("test", dbInteger, 0)
'ajoute la propriété
oTbl.Properties.Append oPrp
'Rafraichit la liste des propriétés
oTbl.Properties.Refresh
End If
'Libération des objets
oDb.Close
Set oTbl=Nothing
Set oDb=Nothing
MsgBox "Propriété ajoutée"
End Sub

La méthode CreateProperty renvoyant un objet de type Property, ce code peut être simplifié par :

Sub ajout()
Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
Set oTbl = Db.TableDefs("Commande")
'Vérifie que la propriété n'existe pas
If Not ExistProperty(oTbl.Properties, "Test") Then
'Crée et ajoute la nouvelle propriété
oTbl.Properties.Append oTbl.CreateProperty("test", dbInteger, 0)
'Rafraîchit la liste des propriétés
oTbl.Properties.Refresh
End If
'Libération des objets
oDb.Close
Set oTbl=Nothing
Set oDb=Nothing
MsgBox "Propriété ajoutée"
End Sub

De même, plutôt que de tester l'existence de la propriété, il est possible de tenter de l'ajouter et de gérer l'erreur si une autre propriété portant le même nom existe déjà.

Sub ajout()
On Error GoTo err
Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
Set oTbl = oDb.TableDefs("Commande")
'Crée et ajoute la nouvelle propriété
oTbl.Properties.Append oTbl.CreateProperty("test", dbText, 0)
'Rafraîchit la liste des propriétés
oTbl.Properties.Refresh
MsgBox "Propriété ajoutée"
Exit Sub
'Gère les erreurs
err:
Select Case err.Number
Case 3367: MsgBox "La propriété existe déjà"
Case Else: MsgBox "Une erreur inconnue est survenue"
End Select
End Sub

4-3 - L'objet TableDef

4-3-1 - Définitions

La collection TableDefs de l'objet Database regroupe l'ensemble des tables de la base de données. Cette collection inclue aussi les tables systèmes et les tables liées. Chaque objet TableDef qui la compose possède une collection d'objets Field (Champ) et une autre d'objets Index. Ces deux autres types d'objet seront étudiés plus loin dans ce chapitre.

Tout comme c'est le cas en mode création dans l'application Access, il est impossible de modifier la structure d'une table liée en utilisant DAO.

4-3-2 - Liste des propriétés

Ci-dessous figure la liste des propriétés appliquables aux objets TableDef.

Certaines de ces propriétés ne sont disponibles en écriture uniquement pour les objets qui n'ont pas encore été ajoutés à la collections Database.TableDefs.

4-3-2-1 - Attributes

Type : Long

La propriété Attributes caractérise la table correspondante. Il s'agit d'une (ou une combinaison) des constantes suivantes :

Constante

Signification

dbAttachExclusive

Utilisable uniquement sur une table liée. Cette valeur indique que la table liée est ouverte en mode exclusif.

dbAttachSavePWD

Utilisable uniquement sur une table liée. Avec cette constante, les informations de Login utilisées pour lier la table sont sauvegardées.

dbSystemObject

Indique une table système.

dbHiddenObject

Indique une table cachée.

dbAttachedTable

Indique une table liée via le moteur Jet.

dbAttachedODBC

Indique une table liée via ODBC.

4-3-2-2 - Connect

Type : String

Il s'agit de la chaîne de connexion utilisée pour une table liée. Sa valeur est nulle pour une table non liée. Cette chaine de connexion prend en compte plusieurs paramètres comme par exemple le nom de l'utilisateur, son mot de passe, etc ... Vous pouvez la consulter visualisant les propriétés de votre table en mode création.

Cette propriété est en lecture seule pour les objets TableDef présents dans la collection Database.TableDefs

4-3-2-3 - DataCreated

Lecture seule.

Type : Date

La propriété DataCreated renvoie la date de création de la table.

4-3-2-4 - Fields

Type : Collection

Cette collection regroupe l'ensemble des champs de la table. Vous pouvez les modifier, en ajouter et en supprimer.

4-3-2-5 - Indexes

Type : Collection

Collection regroupant l'ensemble des index de la table. Vous pouvez les modifier, en ajouter et en supprimer.

4-3-2-6 - LastUpdated

Lecture seule.

Type : Date

La propriété LastUpdated retourne la date et l'heure de la dernière modification apportée à la structure de la table concernée.

4-3-2-7 - Name

Type : String

La prorpiété Name correspond au nom de la table. Ce nom doit être unique au sein de la collection TableDefs de l'objet Database.

Vous trouverez plus loin dans ce chapitre (section 4.3.4.2) un exemple montrant comment renommer une table dans une base de données.

4-3-2-8 - Properties

Type : Collection

La prorpiété Properties est une collection qui regroupe l'ensemble des objets Property de l'objet TableDef.

4-3-2-9 - RecordCount

Lecture seule.

Type : Long

La propriété RecordCount renvoie le nombre d'enregistrements de la table.

4-3-2-10 - SourceTableName

Type : String

Il s'agit du nom d'origine de la table liée. Si l'objet TableDef n'est pas une table liée, cette propriété est en lecture seule et sa valeur est égale à "".

4-3-2-11 - Updatable

Lecture seule.

Type : Boolean

La propriété de Updatable définit si les données provenant de la table peuvent être modifiées.

4-3-2-12 - ValidationRule

Type : String

La propriété ValidationRule définit la règle de validation qui sera utilisée pour valider les données lors d'une mise à jour (Insert compris).

Ainsi, pour obliger l'utilisateur a remplir le champ MonChamp lorsque que le champ Booleen MaCase est coché, nous aurions la règle suivante :

([MonChamp] IS NOT NULL AND [MaCase]) OR NOT ([MaCase])

4-3-2-13 - ValidationText

Type : String

La propriété ValidationText correspond au message qui sera affiché lors d'une mise à jour si les données ne vérifient pas la règle spécifiée dans ValidationRule.

4-3-3 - Liste des méthodes

4-3-3-1 - CreateField

La méthode CreateField crée et retourne un nouvel objet Field qui sera à ajouter par la suite à la collection Database.Tabledefs.

Syntaxe :

Set field = TableDef.CreateField (name, type, size)

Cette méthode sera traitée plus en détail dans la sous partie dédiée aux objets Field.

4-3-3-2 - CreateIndex

La méthode CreateIndex crée un nouvel Index dans la table. Cet Index devra ensuite être ajouté à la collection Indexes de l'objet TableDef pour prendre effet.

Syntaxe :

Set index = tabledef.CreateIndex (name)

4-3-3-3 - CreateProperty

La méthode CreateProperty crée et retourne un nouvel objet Property qu'il vous faudra ensuite ajouter à la collection Properties de l'objet TableDef.

La syntaxe de la méthode est celle illustrée dans la partie : Les propriétés spécifiques.

4-3-3-4 - OpenRecordset

La méthode OpenRecordset ouvre un recordset contenant l'ensemble des enregistrements de la table.

Syntaxe :

Set recordset = object.OpenRecordset (type, options, lockedits)

4-3-3-5 - RefreshLink

La méthode RefreshLink n'est utilisable que sur des tables liées. Elle permet, aprés avoir modifié la propriété Connect, de rafraîchir les informations de connexion entre la table attachée et la source de données.

Syntaxe :

tabledef.RefreshLink

4-3-4 - Opérations sur les tables d'une base de données

4-3-4-1 - Lister les tables d'une base de données

Je vous propose quelques codes utiles pour lister l'ensemble des tables d'une base de données. Nous ferons la distinction entre les tables systèmes et les tables liées. En effet, la propriété Attributes est un masque binaire. L'opérateur AND entre une constante recherchée et la valeur de la propriété effectue une opération binaire renvoyant un nombre égal à 0 si la constante n'est pas utilisée dans la propriété. Ainsi, pour savoir si une table est une table système, il est possible d'utiliser :

If monObjet.Attributes AND dbSystemObjet then .....

Pour lister, l'ensemble des tables systèmes, il suffit donc de parcourir un à un les éléments de la collection TableDefs et de de vérifier si l'expression booléene est vraie ou non.

Sub Lister()
Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
'Pour chaque table
For Each oTbl In oDb.TableDefs
'Si la table est système alors afficher son nom
If oTbl.Attributes And dbSystemObject Then MsgBox oTbl.Name
Next oTbl
End Sub

Si nous souhaitons lister les tables liées, nous aurons :

Sub Lister()
Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
'Pour chaque table
For Each oTbl In oDb.TableDefs
'Si la table est liée alors afficher son nom
If oTbl.Attributes And dbAttachedTable Then MsgBox oTbl.Name
Next oTbl
End Sub

Pour réunir les deux listes, il suffit d'utiliser l'opérateur logique OR (Ou). Ainsi, le code suivant affichera les tables systèmes ainsi que les tables liées.

Sub Lister()
Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
'Pour chaque table
For Each oTbl In oDb.TableDefs
'Si la table est liée ou système alors afficher son nom
If oTbl.Attributes And (dbAttachedTable Or dbSystemObject) Then MsgBox oTbl.Name
Next oTbl
End Sub

Ce code n'est pas à confondre avec :

Sub Lister()
Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
'Pour chaque table
For Each oTbl In oDb.TableDefs
'Si la table est liée et système alors afficher son nom
If oTbl.Attributes And (dbAttachedTable And dbSystemObject) Then MsgBox oTbl.Name
Next oTbl
End Sub

En effet ce dernier liste les tables qui sont à la fois systèmes et liées.

4-3-4-2 - Renommer une table

Renommer une table est une opération extrémement simple. Toutefois, il ne faut pas oublier que le nom de la table doit être unique. Aussi, il faudra implémenter une gestion d'erreur lors d'une telle opération.

Les objets Relations dépendants de la table renommées sont automatiquement mis à jour par le moteur Jet.

Private Function RenommerTable(oBaseDeDonnees As DAO.Database, strAncienNom As String, _
strNouveauNom As String) As Boolean
On Error GoTo err
Dim oTbl As DAO.TableDef
'Cherche la table à modifier
Set oTbl = oBaseDeDonnees.TableDefs(strAncienNom)
'Renomme la table
oTbl.Name = strNouveauNom
'Rafraîchit la collection
oBaseDeDonnees.TableDefs.Refresh
'Renvoie true
RenommerTable = True
Exit Function
err:
Select Case err.Number
Case 3265: MsgBox "Impossible de trouver la table à renommer"
Case 3010: MsgBox "La table " & strNouveauNom & " existe déjà"
Case Else: MsgBox "Une erreur inattendue est survenue"
End Select
End Function

Utilisation :

Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
If RenommerTable(oDb, "Commande", "Commande_Archive") Then
MsgBox "Table renommée avec succès"
End if

4-3-4-3 - Supprimer une table

La suppression d'une table nécessite quelques précautions. Hormis le fait que la table doit exister pour être supprimer, il ne faut pas perdre de vue que la suppression d'une table engendre la suppression des relations qui en dépendent. Aussi dans le cas d'une mauvaise manipulation, vous risquez de supprimer des objets Relations sans vous en rendre compte. Dans ce cas, je préconise d'envoyer un message à l'utilisateur lui demandant confirmation. Il nous faut donc savoir si la table fait partie d'un objet relation ou non. Pour cela, nous utiliserons la fonction ExistRelation suivante :

Private Function ExistRelation(oBaseDeDonnees As DAO.Database, _
strNomTable As String) As Integer
Dim oRlt As DAO.Relation
'Pour chaque objet relation
For Each oRlt In oBaseDeDonnees.Relations
'Si la table est présente dans la relation
If oRlt.Table = strNomTable Or oRlt.ForeignTable = strNomTable Then _
ExistRelation = ExistRelation + 1
Next oRlt
End Function

Cette fonction renvoie le nombre de relations dépendantes de la table passée en paramètre.

Nous pouvons donc écrire la fonction de suppression de table suivante :

Private Function SupprimerTable(oBaseDeDonnee As DAO.Database, _
strNomTable As String)
On Error GoTo err
Dim intNbRlt As Integer
'Compte le nombre de relations dépendantes
intNbRlt = ExistRelation(oBaseDeDonnee, strNomTable)
'Si la table est présente dans au moins une relation
If NbRlt <> 0 Then
'si l'utilisateur ne souhaite pas continuer, sortir de la fonction
If MsgBox("La table " & strNomTable & " est utilisée dans " & _
intNbRlt & " relation(s)." & vbCrLf & "La suppression de cette table entrainera la" & _
" suppression de cette(ces) relation(s)." & vbCrLf & vbCrLf & "Voulez vous continuer ?", _
vbQuestion + vbYesNo, "Suppression de table") = vbNo Then Exit Function
End If
'Supprime la table
oBaseDeDonnee.TableDefs.Delete (strNomTable)
'Rafraichit la collection
oBaseDeDonnee.TableDefs.Refresh
'Renvoie true
SupprimerTable = True
Exit Function
err:
'Gére les erreurs
Select Case err.Number
Case 3265: MsgBox "Impossible de trouver la table à supprimer"
Case Else: MsgBox "Une erreur inattendue est survenue"
End Select
End Function

Utilisation :

Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Set oDb = CurrentDb
If SupprimerTable(oDb, "Commande") Then
MsgBox "Table supprimée"
End If

4-3-4-4 - Créer une nouvelle table

La création d'une table n'ayant que peu d'intéret sans la création de champs, je vous propose d'aborder avant les parties concernant les champs et les index puis de revenir ensuite sur cet exemple.

Dans cet exemple, nous allons créer une table nommée Client possédant trois champs :

- IDClient Clé primaire. Type : Long, numéro automatique

- NomClient Type : Texte. Longueur : 15

- PrenomClient Type : Texte. Longueur : 25

Voici le code correspondant :

Sub CreerTable()
Dim oDb As DAO.Database
Dim oNouvelleTable As DAO.TableDef
Dim oChamp As DAO.Field
Dim oIndex As DAO.Index
'Instancie la base de données
Set oDb = CurrentDb
'Crée la nouvelle table
Set oNouvelleTable = oDb.CreateTableDef("Clients")
'Crée le champ IDClient
Set oChamp = oNouvelleTable.CreateField("IDClient", dbLong)
'Définit le champ en numero_auto
oChamp.Attributes = dbAutoIncrField
'Ajoute le champ à la table
oNouvelleTable.Fields.Append oChamp
'Crée le champ nomClient et l'ajoute
oNouvelleTable.Fields.Append oNouvelleTable.CreateField("NomClient", _
dbText, 15)
'Crée le champ PrenomClient et l'ajoute
oNouvelleTable.Fields.Append oNouvelleTable.CreateField("PrenomClient", _
dbText, 25)
'définit la clé primaire sur l'IDClient
Set oIndex = oNouvelleTable.CreateIndex("PK_IDClient")
oIndex.Primary = True
oIndex.Fields.Append oIndex.CreateField("IdClient")
'Ajoute l'index à la table
oNouvelleTable.Indexes.Append oIndex
'Ajoute la table à la base de données
oDb.TableDefs.Append oNouvelleTable

'Libère les variables
oDb.Close
Set oIndex = Nothing
Set oChamp = Nothing
Set oNouvelleTable = Nothing
Set oDb = Nothing
End Sub

4-4 - L'objet Field

4-4-1 - Définition

Un objet Field représente un champ d'une table ou d'une requête dans une base de données. DAO offre de nombreuses possibilités concernant les objets Field. Il est ainsi possible de créer des champs, d'en supprimer et de les modifier aussi simplement que vous le feriez dans le mode création d'Access. En effet, il existe une réelle analogie entre la liste des propriétés des objets Field et la fenêtre de modification de la structure d'une table. Chaque zone de texte de cette fenêtre correspond à une propriété de l'objet Field.

Je vous propose tout d'abord d'effectuer un tour d'horizon de l'ensemble des propriétés et des méthodes de cet objet, avant de revenir sur des exemples plus spécifiques.

4-4-2 - Liste des propriétés

Vous retrouverez ci-dessous l'ensemble des propriétés des objets Field dans la liste suivante.

Certaines de ces propriétés ne sont disponibles en écriture uniquement pour les objets qui n'ont pas encore été ajoutés à la collections TableDef.Fields.

4-4-2-1 - AllowZeroLength

Type : Boolean

La propriété AllowZeroLength indique si un champ texte accepte les chaines vides. Si la valeur de cette propriété est égale à True, ces valeurs sont acceptées. Dans le cas échéant, une erreur sera levée lorsque que vous tenterez de mettre à jour les données.

4-4-2-2 - Attributes

Type : Long

La propriété Attributes définit les options du champ. Il s'agit d'une une (ou une combinaison) des constantes suivantes :

Constante

Signification

dbAutoIncrField

Correspond à un champ de type Numéro Auto. A n'utiliser que sur les champs de type numérique.

dbDescending

Dans le cas où le champ fait parti d'un index, cette valeur permet d'inverser l'ordre de tri.

dbFixedField

Champ de taille fixe. Valeur par défaut des champs de type numérique.

dbHyperlinkField

Gère les liens hypertext dans un champs mémo.

dbSystemField

Le champ stocke des informations de duplication pour les duplicatas.
Un tel champ ne peut être supprimé.

dbUpdatableField

Le valeur du champ peut être modifiée.

dbVariableField

Le champ peut être modifié. A n'utiliser que sur les champs de type texte.

4-4-2-3 - CollatingOrder

Type : Long

Il s'agit de la méthode utilisée par le moteur pour comparer les valeurs du champ si celui-ci est de type texte.

Les valeurs possibles sont :

Constante

Signification

dbSortGeneral

Général (Français, anglais ...)

dbSortArabic

Arabe

dbSortChineseSimplified

Chinois simplifié

dbSortChineseTraditional

Chinois traditionnel

dbSortCyrillic

Russe

dbSortCzech

Tchèque

dbSortDutch

Néerlandais

dbSortGreek

Grec

dbSortHebrew

Hébreu

dbSortHungarian

Hongrois

dbSortIcelandic

Islandais

dbSortJapanese

Japonais

dbSortKorean

Coréen

dbSortNeutral

Neutre

dbSortNorwDan

Norvégien et danois

dbSortPDXIntl

Paradox International

dbSortPDXNor

Paradox norvégien ou danois

dbSortPDXSwe

Paradox suédois ou finnois

dbSortPolish

Polonais

dbSortSlovenian

Slovène

dbSortSpanish

Espagnol

dbSortSwedFin

Suédois ou finnois

dbSortThai

Thaï

dbSortTurkish

Turc

dbSortUndefined

Indéfini

4-4-2-4 - DataUpdatable

Lecture seule.

Type : Boolean

Lorsque la propriété DataUpdatable est égale à False, il vous est impossible de modifier les valeurs de ce champ. C'est notamment le cas d'un champ auto-incrémenté.

4-4-2-5 - DefaultValue

Type : Variant

Cette propriété correspond à la valeur par défaut du champ. Elle est en lecture/écriture pour les champs issus de TableDef et en lecture seule pour ceux issus de QueryDef et Recordset. Elle n'est pas prise en charge par les objets Fields des collections Database.Indexes et Database.Relations.

Pour un champ de type Long vous pouvez attribuer à cette propriété la valeur : GenUniqueID(). Ainsi à chaque nouvel enregistrement ajouté, le moteur Jet attribue une valeur unique et aléatoire au nouvel enregistrement. Cette valeur reproduit le comportement d'une numérotation automatique aléatoire.

4-4-2-6 - FieldSize

Lecture seule.

Type : Long

La propriété FieldSize, correspond à la taille utilisée dans la base par un champ de type binaire ou mémo.
Cette valeur est exprimée en nombre de caractères pour un champ mémo et en nombre d'octet pour un champ de type binaire.

4-4-2-7 - ForeignName

Type : String

La propriété ForeignName n'est à utiliser que pour les champs d'un objet de type Relation. Elle définit le nom du champ dans la table externe de la relation (clé étrangère). Cette propriété est en lecture/écriture dans le cas d'objets Relation non ajoutés à la collection Database.Relations et en lecture seule pour les objets déjà présents au sein de cette même collection.

4-4-2-8 - Name

Type : String

Il s'agit du nom du champ. Le nom d'un champ doit être unique au sein d'une table.

4-4-2-9 - OrdinalPosition

Type : Integer

La propriété OrdinalPosition permet de définir la position du champ dans la collection Fields de l'objet TableDef. Le premier élément possède la position 0. Cette position conditionne l'ordre d'apparition des champs dans une requête SELECT * FROM ... Notons que si deux champs possèdent la même valeur pour la propriété OrdinalPosition, ces champs sont alors classés par ordre alphabétique.
Cette propriété est en lecture seule pour les objets QueryDef.

4-4-2-10 - Properties

Type : Collection

Collection regroupant l'ensemble des objets Property de l'objet Field.

4-4-2-11 - Required

Type : Boolean

La propriété Required indique si le champs accepte les valeurs nulles. Si cette propriété est égale à True, une erreur sera levée si vous tentez d'affecter une valeur nulle à ce champ.

4-4-2-12 - Size

Type : Integer

La propriété Size définit la taille du champ comme vous pouvez le faire en mode création. Cette propriété n'est en lecture écriture que pour les objets Field qui n'ont pas encore été ajoutés à la collection Fields.

4-4-2-13 - SourceField

Lecture seule.

Type : String

Cette propriété en lecture seule indique dans un objet QueryDef le nom d'un champ et non son alias. Soit une requête nommée R01 :

SELECT NomClient as LeNom FROM Client

Le code suivant affichera LeNom :

Dim oDb As DAO.Database
Dim oQR As DAO.QueryDef
Set oDb = CurrentDb
Set oQR = oDb.QueryDefs("R01")
MsgBox oQR.Fields(0).Name

Cet autre code affichera NomClient :

Dim oDb As DAO.Database
Dim oQR As DAO.QueryDef
Set oDb = CurrentDb
Set oQR = oDb.QueryDefs("R01")
MsgBox oQR.Fields(0).SourceField

Nous pouvons donc écrire la fonction suivante qui retourne le nom d'un champ en fonction de son alias :

Function NomChamp(oBaseDeDonnee As DAO.Database, strRequete As String, strAlias As String) As String
On Error GoTo err
Dim Qdf As DAO.QueryDef
Set Qdf = oBaseDeDonnee.QueryDefs(strRequete)
NomChamp = Qdf.Fields(strAlias).SourceField
Exit Function
'Gère les erreurs
err:
Select Case err.Number
Case 3265
'Si qdf est vide alors la requete n'existe pas
If Qdf Is Nothing Then
MsgBox "Impossible de trouver la requête " & strRequete
Else

MsgBox "Impossible de trouver le champ " & strAlias & " dans la requete " & _
strRequete
End If
Case Else: MsgBox "Une erreur inattendue est survenue"
End Select
End Function

Utilisation :

Dim oDb As DAO.Database
Set oDb = CurrentDb
MsgBox NomChamp(oDb, "R01", "LeClient")

4-4-2-14 - SourceTable

Lecture seule.

Type : String

Cette propriété repose sur le même principe que la précédente. Elle permet de savoir de quelle table provient un champ d'une requête.

Ainsi, avec l'exemple précédent, voici comment connaître la table d'origine du champ LeClient :

Dim oDb As DAO.Database
Dim oQR As DAO.QueryDef
Set oDb = CurrentDb
Set oQR = oDb.QueryDefs("R01")
MsgBox oQR.Fields(0).SourceTable

4-4-2-15 - Type

Type : Integer

Cette propriété définit le type du champ. Il s'agit d'une des constantes suivantes :

Constante

Valeur

Type

dbBigInt

16

Numérique (haute précision)

dbBinary

9

Binaire de longueur fixe (255 octets maxi)

dbBoolean

1

Booléen

dbByte

2

Octet

dbChar

18

Chaîne de caractère de longueur fixe

dbCurrency

5

Monétaire

dbDate

8

Date/Heure

dbDecimal

20

Décimal

dbDouble

7

Double

dbFloat

21

Réel à virgule flottante

dbGUID

15

Identifiant GUID

dbInteger

3

Entier

dbLong

4

Entier long

dbLongBinary

11

Binaire à longueur variable. (OLE)

dbMemo

12

Mémo

dbNumeric

19

Numérique

dbSingle

6

Réel Simple

dbText

10

Texte à longueur fixe

dbTime

22

Heure

dbTimeStamp

23

TimeStamp

dbVarBinary

17

Binaire à longueur variable (255 octets maxi)

4-4-2-16 - ValidationRule

Type : String

La propriété ValidationRule définit la règle de validation qui sera utilisée pour valider les données lors d'une mise à jour (Insert compris).

4-4-2-17 - ValidationText

Type : String

La propriété ValidationText correspond au message qui sera affiché lors d'une mise à jour si les données ne vérifient pas la règle spécifiée dans ValidationRule.

4-4-2-18 - Value

Type : Variant

Pour un objet Recordset, la propriété Value retourne la valeur du champ pour l'enregistrement courant.

4-4-2-19 - VisibleValue

Type : Variant

Cette propriété est utilisable uniquement dans un environnement ODBCDirect. Elle renvoit la valeur actuelle d'un champ lors d'un traitement par lot. Cette valeur est donc plus récente que celle retournée par la propriété OriginalValue

4-4-3 - Liste des méthodes

4-4-3-1 - AppendChunk

La méthode AppendChuk permet d'ajouter des données à la fin d'un champ de type mémo ou binaire. (Collection Recordsets exclusivement) Elle évite notamment de lire le début du champ, de concaténer et de renvoyer la nouvelle valeur. En utilisant la méthode AppendChunk, vous limiter donc le traffic d'informations entre la base de données et le moteur Jet.

Syntaxe :

field.AppendChunk source

L'argument source est de type Variant.

4-4-3-2 - CreateProperty

La méthode CreateProperty crée et retourne un nouvel objet Property qu'il vous faudra ensuite ajouter à la collection Properties de l'objet Field.

La syntaxe de la méthode est celle illustrée dans la partie : Les propriétés spécifiques.

4-4-3-3 - GetChunk

La méthode GetChunk s'applique aux champs des objets Recordset. Elle renvoie le contenu (ou une partie) d'un champ mémo ou binaire dans une variable de type String.

Syntaxe :

Set variable = field.GetChunk (offset, numbytes)

Le paramètre offset de type Long correspond à la position du caractère (ou de l'octet) à partir duquel doit commencer la lecture.

L'argument numbytes détermine le nombre de caractères (ou d'octet) à lire.

4-4-4 - Opérations sur les champs d'un objet TableDef

Seul l'objet TableDef permet de modifier les éléments de sa collection Field. Je vous propose plusieurs exemples afin d'illustrer l'étendue des possibilités qu'offre DAO.

4-4-4-1 - Renommer un champ

Tout comme c'était déjà le cas avec les tables, cette opération nécessite que le nouveau nom soit unique dans la collection Fields de l'objet TableDef.

Les objets Relation et Index utilisant ce champ sont automatiquement mis à jour par le moteur Jet.

Private Function RenommerChamp(oBaseDeDonnees As DAO.Database, strNomTable As String, _
strAncienNomChamp As String, strNouveauNomChamp As String) As Boolean

On Error GoTo err
Dim Tbl As DAO.TableDef
'Récupère la table
Set Tbl = oBaseDeDonnees.TableDefs(strNomTable)
'Renomme le champ
Tbl.Fields(strAncienNomChamp).Name = strNouveauNomChamp
'Renvoie True
RenommerChamp = True
'Gère les erreurs
Exit Function
err:
Select Case err.Number
'Si impossible de trouver l'élément dans la collection
Case 3265
'Si tbl=nothing alors tbl est la cause de l'erreur
If Tbl Is Nothing Then
MsgBox "Impossible de trouver la table : " & strNomTable
Else
MsgBox "Impossible de trouver le champ : " & strAncienNomChamp
End If
Case 3010, 3191: MsgBox "Le champ " & strNouveauNomChamp & " existe déjà"
Case Else: MsgBox "Une erreur inattendue est survenue"
End Select
End Function

Utilisation :

Dim oDb As DAO.Database
Set oDb = CurrentDb
If RenommerChamp (oDb, "Commande", "Reference", "Nouvelle_Reference") then
msgbox "Opération terminée"
End if

4-4-4-2 - Supprimer un champ

La suppression d'un champ est trés délicate. En effet, plusieurs erreurs peuvent être levées au cours de cette opération :

- 3265 : Le champ n'existe pas

- 3280 : Le champ est utilisé par un index

- 3303 : Le champ est utilisé dans une ou plusieurs relations

L'erreur 3303 est difficile à maitriser car même si l'erreur est levée, le champ est quand même supprimé. Toutefois les relations sont toujours présentes et si vous rajoutez par la suite le champ supprimé, la relation va "renaître", ce qui provoque un comportement inattendu.

Il nous faut donc savoir si le champ est l'objet de relations.

Private Function ChampDansRelation(oBaseDeDonnees As DAO.Database, _
strNomTable As String, strNomChamp As String) As Integer
On Error GoTo err
Dim bolUtilise As Boolean
Dim oRlt As DAO.Relation
Dim oFld As DAO.Field
'Parcours les relations
For Each oRlt In oBaseDeDonnees.Relations
bolUtilise = False
If oRlt.Table = strNomTable Then
'Pour chaque champ, contrôle le nom du champ
For Each oFld In oRlt.Fields
If oFld.Name = strNomChamp Then bolUtilise = True
Next oFld
ElseIf oRlt.ForeignTable = strNomTable Then
'pour chaque champ, contrôle le nom étranger
For Each oFld In oRlt.Fields
If oFld.ForeignName = strNomChamp Then bolUtilise = True
Next oFld
End If
'Si la relation utilise le champ, on incremente le resultat
If bolUtilise Then ChampDansRelation = ChampDansRelation + 1
Next oRlt
Exit Function
err:
ChampDansRelation = -1
End Function

Cette fonction renvoie le nombre de relations qui utilisent le champ passé en paramètre.

Utilisation :

Dim oDb as DAO.Database
Set oDb=CurrentDB
MsgBox ChampDansRelation(oDb, "Commande", "Reference")

Cet exemple affichera le nombre de relations utilisant le champ Reference de la table Commande.

La fonction retourne -1 si une erreur est survenue.

Nous pouvons donc écrire la fonction de suppression suivante :

Private Function SupprimerChamp(oBaseDeDonnees As DAO.Database, strNomTable As String, _
strNomChampASupprimer As String) As Boolean

On Error GoTo err
Dim oTbl As DAO.TableDef
'Verifie que le champ ne fait pas partie d'une relation
If ChampDansRelation(oBaseDeDonnees, strNomTable, strNomChampASupprimer) = 0 Then
'Récupère la table
Set oTbl = oBaseDeDonnees.TableDefs(strNomTable)
'Supprime le champ
oTbl.Fields.Delete (strNomChampASupprimer)
'Renvoie True
SupprimerChamp = True
Else
MsgBox "Impossible de supprimer le champ, il est utilisé par une ou plusieurs relations"
End If
Exit Function
err:
Select Case err.Number
'Si impossible de trouver l'élément dans la collection
Case 3265
'Si tbl=nothing alors tbl est la cause de l'erreur
If Tbl Is Nothing Then
MsgBox "Impossible de trouver la table : " & strNomTable
Else
MsgBox "Impossible de trouver le champ : " & strNomChampASupprimer
End If
Case 3280: MsgBox "Impossible de supprimer un champ utilisé par un index"
Case Else: MsgBox "Une erreur inattendue est survenue"
End Select
End Function

Utilisation :

SupprimerChamp oDb, "Commande", "Reference"

4-4-4-3 - Créer un champ

La création d'un champ se décompose en trois étapes :

Un exemple sera certainement plus parlant que de longues phrases, je vous propose de créer un champ AdresseClient dans une table nommée Client.
Ce champ aura pour cractéristiques :

- Type : Texte

- Longueur : 120 caractères

- Chaine vide autorisée : Non

- Null interdit : Oui

Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Dim oFld As DAO.Field
Set oDb = CurrentDb
Set oTbl = oDb.TableDefs("Client")
'Etape 1 : Créer le champ
Set oFld = oTbl.CreateField("AdresseClient", dbText, 120)
'Etape 2 : Définit les propriétés
oFld.AllowZeroLength = False 'Chaine vide autorisée : Non
oFld.Required = True         'Null interdit : Oui
'Etape 3 : Ajout du champ à la table
oTbl.Fields.Append Fld
'Rafraichit la collection
oTbl.Fields.Refresh

Il est important de respecter l'ordre de chaque étape. Si vous ajouter le champ à la collection Fields avant de lui avoir affecter l'ensemble de ses propriétés, vous vous apercevrez que certaines de ces propriétés ne sont plus accessibles en écriture.

Nous n'avons pas traité ici la gestion d'erreur. Celle ci exactement la même que pour la fonction qui renomme un champ. En effet, le plus grand risque pour ce programme est d'utiliser un nom de champ qui existe déjà.

4-4-4-4 - Dupliquer un champ

Je vous propose ici un code qui peut s'avérer utile lorsque vous souhaiter créer un champ identique à un autre. Le principe est simple, nous partons de deux objets Field. Le premier sera utilisé comme source du clonage. Nous allons donc parcourir chaque propriété (exceptée la propriété Name) du champ source et les réécrire dans le champ de destination.

Certaines de ces propriétés risquent d'être en lecture seule. Il nous faut donc déleguer la lecture et l'écriture des propriétés à une autre procédure afin de ne pas faire stopper le programme à la première erreur rencontrée.

Public Sub CloneChamp(oFldSource As DAO.Field, oTableDestination As DAO.TableDef, _
strNouveauNom As String)
On Error GoTo err
Dim oFld As DAO.Field
Dim oPrp As DAO.Property
'Crée le champ
Set oFld = oTableDestination.CreateField(strNouveauNom)
'Pour chaque propriete
For Each oPrp In oFldSource.Properties
'copier la propriété s'il ne s'agit pas du nom
If oPrp.Name <> "Name" Then _
EcrirePropriete oPrp, oFld
Next oPrp
'Ajoute le champ
oTableDestination.Fields.Append oFld
Exit Sub
err:
Select Case err.Number
Case 3010, 3191: MsgBox "Le champ " & strNouveauNom & " existe déjà"
Case Else: MsgBox "Une erreur inattendue est survenue"
End Select
End Sub

Private Sub EcrirePropriete(oPropriete As DAO.Property, _
oChampDestination As DAO.Field)
On Error GoTo err
'Copie la propriété
With oChampDestination.Properties
.Item(oPropriete.Name) = oPropriete.Value
.Refresh
End With
'On ne traite pas les erreurs
err:
End Sub

Pour dupliquer le champ AdresseClient de la table Client dans la table SauvegardeClient nous utiliserons :

Dim oDb As DAO.Database
Dim oTblSource As DAO.TableDef, oTblDestination As DAO.TableDef
Dim oFld As DAO.Field
Set oDb = CurrentDb
'Stocke les deux tables
Set oTblSource = oDb.TableDefs("Client")
Set oTblDestination = oDb.TableDefs("SauvegardeClient")
'Stocke le champ
Set oFld = oTblSource.Fields("AdresseClient")
'Clone le champ
CloneChamp oFld, oTblDestination, "AdresseClient2"

4-5 - L'objet Index

4-5-1 - Définitions

Nous n'allons pas reprendre ici la définition d'un index. Je vous renvoie pour cela vers d'autres tutoriels de ce site. Toutefois, rappelons sommairement qu'un index permet de faciliter l'accès aux données dans une table lors d'une recherche et qu'il permet aussi de poser des contraintes sur les données (Notion de clé primaire et de doublons).

Un index peut être composé d'un ou plusieurs champs, il possède donc une collection Fields recensant ces champs.

4-5-2 - Liste des propriétés

4-5-2-1 - DistinctCount

Lecture seule.

Type : Long

La propriété DistinctCount renvoie le nombre de valeurs uniques présentes dans la table. Dans le cas d'un index mono-champ, il s'agit du nombre de valeurs distinctes dans ce champ (équivalent d'une requête SELECT DISTINCT MonChamp ...). Dans le cas d'un index composé de plusieurs champs, cette valeur correspond au nombre de combinaisons distinctes des valeurs de ces champs au sein de la table (équivalent d'une requête SELECT DISTINCT MonChamp1,MonChamp2 ...).

4-5-2-2 - Fields

Type : Collection

Cette collection regroupe l'ensemble des champs composant l'index. Chaque objet Field de cette collection doit posséder le même nom qu'un objet Field de la table concernée.

4-5-2-3 - Foreign

Lecture seule.

Type : Boolean

Lorsque la propriété Foreign d'un index est égale à True, cela signifie que l'index est une clé étrangère. C'est notamment le cas pour les index ajoutés automatiquement par Access lorsque vous créez des relations entre les tables.

4-5-2-4 - IgnoreNulls

Type : Boolean

Si vous définissez la propriété IgnoreNulls à True, les valeurs nulles ne seront pas indéxées. Cela peut être utile si vous prévoyer d'enregistrer un grand nombre de valeur nulles.

4-5-2-5 - Name

Type : String

Cette propriété correspond au nom de l'index. Ce nom doit être unique dans la collection Indexes de l'objet TableDef correspondant.

Prévoyez des noms d'index aussi clairs que possible. Aussi certains préfixent le nom de leurs index par les initiales de leur rôle. Ainsi, une clé primaire sera notée PK_MonChamp (PK = Primary Key).

4-5-2-6 - Properties

Type : Collection

Collection regroupant l'ensemble des objets Property de l'objet Index.

4-5-2-7 - Required

Type : Boolean

Si la propriété Required est égale à True, cela signifie que les champs de l'index doivent tous recevoir une valeur, sans quoi, lors des mises à jour, une erreur sera levée.

4-5-2-8 - Unique

Type : Boolean

Lorsque la propriété Unique est égale à True, les doublons sont interdits dans les champs de l'index.

Dans un index multi-colonnes, les valeurs A A et A B ne sont pas des doublons.

4-5-3 - Liste des méthodes

Comme vous allez le remarquer, l'objet Index dispose de trés peu de méthodes. Qui plus est, ces méthodes ont déjà été traitées plus haut.

4-5-3-1 - CreateField

Cette méthode est la même que celle appliquée aux objets TableDef, à la différence prés quelle ne propose qu'un seul paramètre : le nom du champ. Ce nom doit être identique à celui du champ de la table sur lequel repose l'index.

Syntaxe :

Set field = index.CreateField (name)

4-5-3-2 - CreateProperty

Cette méthode n'est plus à présenter, et pour cause, nous la retrouvons à chaque chapitre de ce tutoriel. Aussi, je vous renvoie vers le chapitre des 4.2.5 Propriétés spécifiques.

4-5-4 - Opérations sur les Index

Je vous propose deux petits exemples afin de mettre en pratique les notions abordées dans cette partie.

4-5-4-1 - Créer un index

Soit une table Client possédant plusieurs champs dont NumeroClient. Nous allons créer une clé primaire sur ce champ.

Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
Dim oFld As DAO.Field
Dim oInd As DAO.Index
'Instancie la base
Set oDb = CurrentDb
'Instancie la table
Set oTbl = oDb.TableDefs("Client")
'Crée l'index en le nommant PK_Client
Set oInd = oTbl.CreateIndex("PK_Client")
'Cree le champs dans l'index
Set oFld = oInd.CreateField("NumeroClient")
'Ajoute le champ à la collection Fields
oInd.Fields.Append oFld
'Définit la clé primaire
oInd.Primary = True
'Ajoute l'index à la table
oTbl.Indexes.Append oInd
'Rafraichit la collection
oTbl.Indexes.Refresh

4-5-4-2 - Supprimer une clé primaire

Afin d'illustrer la suppression d'un index je vous propose de traiter le cas, où nous souhaitons supprimer la clé primaire de la table. Il nous faut donc parcourir l'ensemble des index de l'objet TableDef et les supprimer si leur propriété Primary est égale à True.

Private Sub SupprimerClePrimaire(oTbl As DAO.TableDef)
On Error GoTo err
Dim oInd As DAO.Index
'Parcours les index
For Each oInd In oTbl.Indexes
'S'il s'agit d'une clé primaire, alors le supprimer
If oInd.Primary Then
oTbl.Indexes.Delete (oInd.Name)
End If
Next oInd
Exit Sub
err:
MsgBox "Une erreur inattendue est survenue"
End Sub

Utilisation :

Dim oDb As DAO.Database
Dim oTbl As DAO.TableDef
'Instancie la base
Set oDb = CurrentDb
'Instancie la table
Set oTbl = oDb.TableDefs("Client")
'Supprime la clé primaire
SupprimerClePrimaire oTbl

4-6 - L'objet Relation

4-6-1 - Définitions

Certaines applications sont jugées sur leur performance ou leur ergonomie. Lorsqu'il s'agit d'une base de données, les critères de sélection ne sont plus les mêmes. Le rôle principal d'un SGBD est de stocker des données et ce stockage doit être réalisé dans les meilleures conditions. Il serait dramatique que certaines données soient perdues fréquemment. Une application Access doit donc garantir la cohérence et l'intégrité des données. Imaginons une table Commande et une table Client, il serait illogique d'affecter une commande à un client non recensé dans la table Client. Afin d'éviter ce risque , le moteur Jet permet de créer des contraintes d'intégrités par le biais de ses objets Relations qui obligeront à saisir un client valide dans la table des commandes.

4-6-2 - Liste des propriétés

4-6-2-1 - Attributes

Type : Long

La propriété Attributes correspond au type de la contrainte représentée par l'objet Relation. La valeur de cette propriété doit être une (ou une combinaison) des constantes suivantes :

Constante

Signification

dbRelationUnique

Relation de type un à un.

dbRelationDontEnforce

L'intégrité référentielle n'est pas appliquée.

dbRelationUpdateCascade

Les mises à jours sont répercutées en cascade.

dbRelationDeleteCascade

Les suppressions sont répercutées en cascade.

dbRelationLeft

Les jointures seront de type Left par défaut.

dbRelationRight

Les jointures seront de type Rigth par défaut.

4-6-2-2 - Fields

Type : Collection

Cette collection regroupe l'ensemble des champs utilisés par la relation. Vous devez utiliser la méthode Relation.CreateField pour créer de nouveaux champs dans la relation et les ajouter à la collection Fields à l'aide de la méthode Append.

Chaque objet Field de la relation doit posséder le nom du champ concerné dans la table spécifiée dans la propriété Table. Ce champ aura comme propriété ForeignName, le nom d'un champ de la table spécifiée dans la propriété ForeignTable.

4-6-2-3 - ForeignTable

Type : String

La propriété ForeignTable correspond au nom de la table externe de la relation. Ce nom doit être celui d'un objet TableDef présent dans la collection TableDefs de l'objet Database.

4-6-2-4 - Name

Type : String

La propriété Name représente le nom de la relation. Il doit être unique au sein de la collection Database.Relations.

L'utilisation de nom précis facilitera les opérations de maintenance sur la base de données. Ainsi, une relation entre une table commande et une table client sera nommée Rlt_CommandeClient. Evitez d'appeler vos objets Relation1, Table1, Requete1...

4-6-2-6 - Properties

Type : Collection

La collection Properties regroupe l'ensemble des propriétés de l'objet Relation.

4-6-2-7 - Table

Type : String

La propriété Table correspond au nom de la table principale sur laquelle porte la relation. Il s'agit de la table possédant la clé primaire utilisée dans la relation. A contrario, la propriété ForeignName correspond à la table possédant la clé étrangère de la relation.

4-6-3 - Liste des méthodes

Les objets de type Relation ne possède qu'une seule méthode : CreateField. Celle ci permet de créer un champ à ajouter à la relation.

Syntaxe :

Set field = relation.CreateField (name)

Name correspond au nom du champ de la clé primaire utilisée dans la relation.

4-6-4 - Exemple de définition des propriétés

Considérons deux tables et la relation suivante :

Paramètres de la relation :

Les propriétés d'une telle relation seront définies ainsi :

- Attributes : dbRelationUpdateCascade

- Fields : Un objet Field nommé "NumClient" et ayant comme propriété ForeignName : "IDClient"

- ForeignTable : "Commande"

- Name : "Rlt_CommandeClient"

- PartialReplica : False (Non utilisé)

- Table : "Client"

4-6-5 - Opérations sur les relations

Je vous propose une suite de quelques exemples de code VBA afin de manipuler les objets Relations

4-6-5-1 - Créer une relation

Reprenons l'exemple ci-dessus. Je vous livre le code correspondant à une telle relation.

La première méthode consiste à créer la relation et affecter à chacune des propriétés sa valeur correspondante.

Dim oDb As DAO.Database
Dim oRlt As DAO.Relation
Dim oFld As DAO.Field
Set oDb = CurrentDb
'Crée la relation
Set oRlt = oDb.CreateRelation
'Définit les propriétés
oRlt.Attributes = dbRelationUpdateCascade
oRlt.ForeignTable = "Commande"
oRlt.Name = "Rlt_CommandeClient"
oRlt.Table = "Client"
'Crée le champ dans la relation
Set oFld = oRlt.CreateField("NumClient")
'Définit le nom de la clé externe
oFld.ForeignName = "IDClient"
'Ajoute le champ
oRlt.Fields.Append oFld
'Rafraîhit la collection Relations
oDb.Relations.Refresh
'Ajoute la relation
oDb.Relations.Append oRlt
'Rafraîhit la collection Relations
oDb.Relations.Refresh
'Ferme la base de données
oDb.Close
Set oDb = Nothing

La seconde méthode consite à utiliser l'ensemble des arguments de la méthode CreateProperty. En effet celle-ci permet d'initialiser le nom de la relation, de la table, de la table externe ainsi que les attributs.

Syntaxe :

Set relation = database.CreateRelation (name, table, foreigntable, attributes)

Notre code devient alors :

Dim oDb As DAO.Database
Dim oRlt As DAO.Relation
Dim oFld As DAO.Field
Set oDb = CurrentDb
'Crée la relation
Set oRlt = oDb.CreateRelation("Rlt_CommandeClient", "Client", _
"Commande", dbRelationUpdateCascade)
'Crée le champ
Set oFld = oRlt.CreateField("NumClient")
'Définit le nom de la clé externe
oFld.ForeignName = "IDClient"
'Ajoute le champ
oRlt.Fields.Append oFld
'Rafraîhit la collection Relations
oDb.Relations.Refresh
'Ajoute la relation
oDb.Relations.Append oRlt
'Rafraîhit la collection Relations
oDb.Relations.Refresh
'Ferme la base de données
oDb.Close
Set oDb = Nothing

4-6-5-2 - Compter les relations utilisant un champ donné

Cette fonction a déjà été utilisé lors de l'opération qui consistait à supprimer un champ dans un objet TableDef.

Le principe est simple, un champ est utilisé par une relation si :

- La table dont il provient est présent dans la propriété Table de la relation et que le nom d'un champ de la relation est égal au nom de ce champ.

- La table dont il provient est présent dans la propriété ForeignTable de la relation et qu'au moins un champ de cette relation possède une propriété ForeignName égale au nom de ce champ.

Il nous suffit donc de boucler sur l'ensemble des objets Relation de la base de données.

Private Function ChampDansRelation(oBaseDeDonnees As DAO.Database, _
strNomTable As String, strNomChamp As String) As Integer
On Error GoTo err
Dim bolUtilise As Boolean
Dim oRlt As DAO.Relation
Dim oFld As DAO.Field
'Parcours les relations
For Each oRlt In oBaseDeDonnees.Relations
bolUtilise = False
If oRlt.Table = strNomTable Then
'Pour chaque champ, contrôle le nom du champ
For Each oFld In oRlt.Fields
If oFld.Name = strNomChamp Then bolUtilise = True
Next oFld
ElseIf oRlt.ForeignTable = strNomTable Then
'pour chaque champ, contrôle le nom étranger
For Each oFld In oRlt.Fields
If oFld.ForeignName = strNomChamp Then bolUtilise = True
Next oFld
End If
'Si la relation utilise le champ, on incremente le resultat
If bolUtilise Then ChampDansRelation = ChampDansRelation + 1
Next oRlt
Exit Function
err:
ChampDansRelation = -1
End Function

Il devient alors possible de connaître le nombre de relations utilisant le champ NumClient de la table Client.

Utilisation :

Dim oDb as DAO.Database
Set oDb=CurrentDB
MsgBox ChampDansRelation(oDb, "Client", "NumClient")

4-6-5-3 - Supprimer les relations autour d'une table

Il peut s'avérer par fois utile de supprimer les relations portant sur une table avant de pouvoir modifier la structure de la table. Cette opération peut s'avérer fastidieuse et je vous suggère de créer une fonction automatisant cette tâche.

Public Function SupprimerRelationTable(oBaseDeDonnees As _
DAO.Database, strNomTable As String) As Integer
Dim oRlt As DAO.Relation
'Pour chaque relation,
For Each oRlt In oBaseDeDonnees.Relations
'si la table est utilisée
If oRlt.Table = strNomTable Or oRlt.ForeignTable = strNomTable Then
'Supprime la relation
oBaseDeDonnees.Relations.Delete oRlt.Name
oBaseDeDonnees.Relations.Refresh
'Incrémente le compteur
SupprimerRelationTable = SupprimerRelationTable + 1
End If
Next oRlt
End Function

La fonction SupprimerRelationTable retourne le nombre de relations supprimées.

Utilisation :

Dim oDb As DAO.Database
Dim oRlt As DAO.Relation
Set oDb = CurrentDb
'Supprime les relations de la table Client
MsgBox SupprimerRelationTable(oDb, "Client")

4-7 - L'objet QueryDef

Nous sommes sur le point d'aborder le dernier objet de la partie DDL du modèle DAO. Cette partie commencera par une rapide présentation de l'objet, suivie de la liste des propriétés et des méthodes puis enfin, quelques exemples d'utilisation en VBA.

4-7-1 - Définitions

Access est un des rares SGBDR permettant de stocker des requêtes SQL dans la base de données sans qu'il ne s'agissent de vues. Certes, une vue est le résultat de cette requête mais son contenu est statique. Pour visualiser les modifications intervenues dans le jeu d'enregistrements entre deux instants, il est nécessaire de recréer la vue. Une requête stockée dans une base de données Access est dynamique. Elle est réexecutée à chaque fois que vous la réouvrez. De telles requêtes sont modélisées par l'objet QueryDef dans DAO.

Ces requêtes peuvent être de plusieurs types : sélection, union, insertion, mise à jour, suppression, analyse croisée ...

Requêtes paramétrées :

DAO propose de gérer les paramètres des requêtes via la collection Parameters de l'objet QueryDef. Ces requêtes sont trop souvent oubliées dans Microsoft Access et remplacées par des requêtes SQL codées directement dans VBA. Pourtant, la manipulation de ces requêtes est trés simple :

PARAMETERS Param_Num Text ( 10 );
SELECT *
FROM Client
WHERE NumClient=Param_Num;

La clause PARAMETERS liste l'ensemble des paramètres avec leur type et (optionnellement) leur taille. La seconde partie de la requête, est celle que vous auriez écrit sans paramètre.

Ainsi, pour ouvrir un Recordset sur le client possédant le numéro AF36, le code VBA serait :

Dim oDb As DAO.Database
Dim oQdf As DAO.QueryDef
Dim oRst As DAO.Recordset
Set oDb = CurrentDb
Set oQdf = oDb.QueryDefs("R01")
oQdf.Parameters("Num").Value = "AF36"
Set oRst = oQdf.OpenRecordset

Afin de comparer, voici le même code sans utiliser les requêtes paramétrées :

Dim oDb As DAO.Database
Dim oSQL As String
Dim oRst As DAO.Recordset
Dim StrSQL As String
Set oDb = CurrentDb
StrSQL = "SELECT * FROM Client " & _
"WHERE NumClient=" & Chr(34) & "AF36" & Chr(34)
Set oRst = oDb.OpenRecordset(StrSQL)

L'utilisation des requêtes paramétrées apparait donc plus intuitive et évite de manipuler des fonctions de conversion de chaîne. De plus, si demain, nous souhaitons modifier notre requête pour y ajouter une jointure, il nous suffit de modifier le code SQL correspondant dans la requête paramétrée. Si au contraire nous n'utilisons pas ces requêtes, il nous faut alors modifier notre code VBA aux différents endroit où la "requête" est mentionnée.

Si vous ouvrez un objet Database Db2 depuis la base de données Db1 et que vous éxecutez un objet QueryDef de Db2, les données seront prélevées depuis Db2 et non dans Db1. Chaque objet QueryDef travaille sur les données de l'objet Database qui le contient.

4-7-2 - Liste des propriétés

Vous trouverez ci-dessous la liste des propriétés disponibles pour les objets QueryDef.

La propriété Prepare n'est pas documentée dans ce tutoriel.

4-7-2-1 - Connect

Lecture seule.

Type : String

La propriété Connect renvoie la chaine de connexion utilisée par la requête lorsque celle ci provient d'une autre base de données.

4-7-2-2 - DateCreated

Lecture seule.

Type : Date

Cette propriété renvoie la date à laquelle a été créé la requête.

4-7-2-3 - Fields

Lecture seule.

Type : Collection

Une nouvelle fois, nous rencontrons cette collection qui regroupe l'ensemble des champs retournés par la requête.

Notez que vous pouvez différencier le nom d'un champ et son alias en utilisant la propriété SourceField de l'objet Field.

4-7-2-4 - LastUpdated

Lecture seule.

Type : Date

Cette propriété renvoie la date à laquelle a été modifiée la requête pour la dernière fois.

4-7-2-5 - MaxRecords

Type : Long

La propriété MaxRecords correspond au nombre d'enregistrements à renvoyer au maximum. Cette propriété peut être utilisée lorsque le poste client ne dispose pas de ressources suffisantes afin de traiter l'ensemble des données.

Cette propriété est disponible uniquement pour les requêtes utilisant une source de données ODBC.

4-7-2-6 - Name

Type : String

La propriété Name représente le nom de la requête. Il doit être unique au sein de la collection Database.QueryDefs.

Lorsque vous utilisez la méthode CreateQueryDef et que vous ne spécifiez pas l'argument Name, la requête n'est pas sauvegardée dans la base de données à la fin du traitement.

4-7-2-7 - Parameters

Type : Collection

Cette collection regroupe l'ensemble des paramètres d'un objet QueryDef. Il est impossible d'ajouter ou de supprimer des éléments de cette collection.

Un exemple d'utilisation de requête paramétrée est disponible dans les définitions des QueryDefs ci-dessus.

4-7-2-8 - Properties

Type : Collection

La collection Properties regroupe l'ensemble des propriétés de l'objet QueryDef.

4-7-2-9 - RecordsAffected

Lecture seule.

Type : Long

Dans le cas d'une requête action (Insert,Update,Delete), la propriété RecordsAffected retourne le nombre d'enregistrements affectés par l'ordre SQL.

4-7-2-10 - ReturnsRecords

Type : Boolean

Cette propriété définit ou renvoie une valeur indiquant si une requête retourne des enregistrements.

La propriété ReturnsRecords est disponible uniquement pour les requêtes SQL directes.

4-7-2-11 - SQL

Type : String

La propriété SQL correspond au code SQL de la requête.

Cette propriété correspond à l'argument SQL de la méthode Database.CreateQueryDef.

4-7-2-12 - Type

Type : Long

La propriété Type renvoie le type de la requête. Cette propriété est définie automatiquement lorsque vous créez l'objet QueryDef. Toutefois, elle peut vous permettre de recenser les objets QueryDef suivant leur rôle.

Les valeurs possibles sont :

Constante

Signification

dbQAction

Action

dbQAppend

Ajout

dbQCompound

Non documentée

dbQCrosstab

Analyse croisée

dbQDDL

Définition de données

dbQDelete

Suppression

dbQMakeTable

CreateTable

dbQProcedure

Procédure stockée

dbQSelect

Sélection

dbQSetOperation

Union

dbQSPTBulk

Requête ne renvoyant pas d'enregistrement

dbQSQLPassThrough

Requête SQL Directe

dbQUpdate

Mise à jour

4-7-2-13 - Updatable

Lecture seule.

Type : Boolean

Cette propriété renvoie True si les données de la requête ne peuvent être modifiées.

4-7-3 - Liste des méthodes

4-7-3-1 - CreateProperty

La méthode CreateProperty crée un nouvel objet Property. Plus de détails sont disponibles dans le chapitre 4.2.5 Propriétés spécifiques.

4-7-3-2 - Execute

La méthode Execute éxecute une requête Action. Une erreur sera levée si vous tentez d'exécuter une requête de sélection.

Syntaxe :

querydef.Execute options

L'argument options doit être une (ou une combinaison) des constantes suivantes :

Constante

Signification

dbDenyWrite

Interdit l'accés en écriture pour les autres utilisateurs

dbInconsistent

(Valeur par défaut) Exécute des mises à jour sans vérifier la cohérence (intégrité réferentielle)

dbConsistent

Exécute des mises à jour en vérifiant la cohérence

dbSQLPassThrough

Exécute une requête SQL Direct

dbFailOnError

En cas d'erreur, les mises à jour sont annulées

dbSeeChanges

Génère une erreur d'exécution si un autre utilisateur modifie les données que vous êtes en train de modifier

Vous pouvez utiliser la propriété RecordsAffected pour connaître le nombre d'enregistrements modifiés.

4-7-3-3 - OpenRecordset

La méthode OpenRecordset ouvre un jeu d'enregistrements sur le résultat de la requête.

Syntaxe :

Set recordset = object.OpenRecordset (type, options, lockedits)

Cette méthode sera largement abordée dans le chapitre suivant.

4-7-4 - Opérations sur les requêtes

4-7-4-1 - Création d'une requête

Dans notre exemple nous allons créer une requête de sélection complète de la table clients. Il s'agit d'une requête simple et la méthode à appliquer est la même pour tout type de requête.

Sub CreerRequete()
On Error GoTo Err
Dim oDb As DAO.Database
Dim strCodeSql As String
'Instancie l'objet database
Set oDb = CurrentDb
'Stocke le code SQL dans une variable
strCodeSql = "SELECT * FROM Client"
'Crée la requête
oDb.CreateQueryDef "R01_SelectionClient", strCodeSql

Finally:
oDb.Close
Set oDb = Nothing

Err:
'Gére les erreurs
Select Case Err.Number
Case 3012: MsgBox "La requête existe déjà"
Case Else: MsgBox "Une erreur inconue est survenue"
End Select
Resume Finally
End Sub

4-7-4-2 - Modifier le code d'une requête

Afin de modifier le code SQL, il faut procéder en deux étapes :

- Récuperer l'objet QueryDef correspondant (S'il existe).

- Modifier la propriété SQL de l'objet.

Public Function ModifierSQL(oBaseDeDonnees As DAO.Database, _
strNomRequete As String, strCodeSQL As String) As Boolean
On Error GoTo Err
Dim oQdf As DAO.QueryDef
'Instancie l'objet QueryDef
Set oQdf = oBaseDeDonnees.QueryDefs(strNomRequete)
'Modifie le code SQL
oQdf.SQL = strCodeSQL
'Renvoie True
ModifierSQL = True
Exit Function
Err:
'Gere les erreurs
Select Case Err.Number
Case 3265: MsgBox "Impossible de trouver la requête à modifier"
Case Else: MsgBox "Une erreur inattendue est survenue"
End Select
End Function

Utilisation :

Dim oDb As DAO.Database
Set oDb = CurrentDb
If ModifierSQL(oDb, "R01_SelectionClient", "SELECT NumClient FROM Client") Then
MsgBox "Le code SQL de la requête a été modifié avec succés"
End If

4-7-4-3 - Lister les requêtes

La propriété Type retourne le type d'un objet QueryDef. Il est donc possible de lister l'ensemble des requêtes de sélection.

Dim oDb As DAO.Database
Dim oQdf As DAO.QueryDef
'Instancie l'objet Database
Set oDb = CurrentDb
'Boucle sur les objets QueryDef
For Each oQdf In oDb.QueryDefs
'S'il s'agit d'une requête de sélection, alors afficher son nom
If oQdf.Type = dbQSelect Then MsgBox oQdf.Name, , "Sélection"
Next oQdf

5 - Accès aux données

5-1 - Définition

Sous Visual Basic, une application est capable d'accèder aux données via un objet Recordset. Cet objet correspond à un jeu d'enregistrements communément appelé curseur (de l'anglais CURSOR : CURrent Set Of Rows). Si vous faites vos premiers pas dans le monde des Recordset, vous pouvez imaginer cela comme le tableau d'une requête en mode feuille de données. Le Recordset est alors composé de plusieurs lignes (enregistrements) et de plusieurs colonnes (champs). Lorsque vous accédez à la valeur d'un champ, vous le faîtes pour l'enregistrement courant dans le Recordset. Il en est de même dans la feuille de données d'une requete. La ligne courante est alors matérialisée par un triangle dans le sélecteur d'enregistrement. Celle ci pourrait se matérialiser par le sélecteur d'enregistrement dans une feuille de données.

Les Recordset donnent donc la possibilité de récuperer le résultat d'une requête dans une variable, de l'analyser, de le modifier, etc... tout comme vous le feriez manuellement dans une feuille de données ou un formulaire.

5-1-1 - Les différents types de Recordset

Il existe cinq types de Recordset :

1. Recordset de type Table :

Un Recordset de type Table permet d'accéder directement au contenu d'une table. Son contenu est dynamique, ce qui signifie que les mises à jour sont directement répercutées dans le jeu d'enregistrement. La source d'un tel Recordset est le nom d'une table.

Attention ce type est incompatible avec les tables liées (provenant d'une autre base de données)

2. Recordset de type Dynaset :

Un Recordset de type Dynaset correspond au résultat d'une instruction SQL retournant des enregistrements. Son contenu est dynamique et sa source peut être soit le nom d'une table, d'une requête ou bien une instruction SQL valide.

3. Recordset de type Snapshot :

Un Recordset de type Snapshot correspond à une photographie des données à un instant donné (son ouverture). Les modifications apportées dans la base de données aprés l'ouverture d'un tel curseur ne sont pas répercutées dans le jeu d'enregistrements. Son contenu est donc statique et sa source est définit comme celle d'un Recordset de type Dynaset.

4. Recordset de type ForwardOnly :

Il s'agit d'un Recordset de type Snapshot à la différence qu'il ne permet de se déplacer exclusivement vers l'avant. Il est impossible de repartir au début du jeu d'enregistrement, ni même de reculer au cours de la lecture des données.

5. Recordset de type Dynamic :

Ce type de Recordset est semblable au type Dynaset à la différence qu'il s'applique exclusivement aux sources de données ODBC Direct.

5-2 - Ouvrir et fermer un recordset

Depuis Access et VBA, il est possible d'utiliser plusieurs méthodes afin d'ouvrir un jeu d'enregistrements.

5-2-1 - Depuis un objet Database

L'objet Database (et donc indirectement CurrentDB) est muni de la méthode OpenRecordset qui instancie un nouvel objet Recordset et l'ajoute à la collection Database.Recordsets.

La syntaxe de cette méthode est la suivante :

Set recordset = Database.OpenRecordset (source, [type, options, lockedits])

source : Il s'agit de la source d'enregistrements du Recordset. Il peut s'agir du nom d'une table, d'une requête ou d'une instruction SQL valide retournant des enregistrements (SELECT). Dans le cas d'un Recordset de type Table, cet argument est restreint au nom d'une table.

Pour être valide, l'instruction SQL doit tenir compte des différents types de champ dans l'expression des critères. Ainsi, si le champ NomClient est de type texte, la variable source sélectionnant le client nommé Dupont sera :

Source="SELECT * FROM Client WHERE NomClient=" & chr(34) & "Dupont" & chr(34)

La fonction Chr(34) permet d'encadrer un critère de type texte avec des guillemets. En effet, nous n'aurions pas pu écrire :

Source="SELECT * FROM Client WHERE NomClient="Dupont""

En effet, dans ce cas, le " avant Dupont correspondrait à la fermeture de guillemet associée au premier caractère " (avant SELECT). Une erreur serait donc levé par le compilateur. Une solution possible est donc d'utiliser le code Ascii du caractère ". Le contenu de la variable utilisant la fonction Chr sera aprés concaténation :

SELECT * FROM Client WHERE NomClient="Dupont"

Toutefois, il reste encore un problème. Si dans la valeur recherchée figure un guillemet, le moteur Jet va l'interpréter lui aussi comme une fin de chaine de caractère. La solution est de doubler les guillemets dans l'expression du critère :

Source="SELECT * FROM Client WHERE NomClient=" & chr(34) & Replace(MaVariable,chr(34),chr(34) & chr(34)) & chr(34)

Ainsi, si MaVariable est égale à Monsieur "X", alors la fonction Replace retournera Monsieur ""X"". La source du Recordset sera, aprés concaténation :

SELECT * FROM Client WHERE NomClient="Monsieur ""X"""

Le type Date est plus simple à traiter, il faut encadrer la valeur du critère par des #. Notons tout de même que les dates doivent être en format américain : mm/jj/yyyy.

Un recordset sélectionnant les commandes du 10 décembre 2003 sera initialisé avec la source suivante :

Source="SELECT * FROM Commande WHERE DateCommande=#12/10/2003#"

Type : Cet argument correspond au type du recordset à générer. Les constantes disponibles sont :

Constante

Type de recordset

dbOpenTable

Table

dbOpenDynamic

Dynamique (ODBC Direct)

dbOpenDynaset

Feuille de réponse dynamique

dbOpenSnapshot

Instantané

dbOpenForwardOnly

En avant seulement

Options : Ce paramètre définit les paramètres optionnels du Recordset. Il s'agit d'une (ou une combinaison) des constantes suivantes :

Constante

Effets

dbAppendOnly

Permet aux utilisateurs d'ajouter de nouveaux enregistrements à l'objet Recordset, tout en leur interdisant de modifier ou de supprimer les enregistrements existants (objet Recordset de type Feuille de réponses dynamique Microsoft Jet (Dynaset) uniquement).

dbSQLPassThrough

Transmet une instruction SQL à une source de données ODBC connectée Microsoft Jet en vue de son traitement (objet Recordset de type Instantané Microsoft Jet (Snapshot) uniquement).

dbSeeChanges

Génère une erreur d'exécution si un utilisateur modifie les données en cours de modification par un autre utilisateur (objet Recordset de type Feuille de réponses dynamique Microsoft Jet (Dynaset) uniquement).

dbDenyWrite

Interdit aux autres utilisateurs de modifier ou d'ajouter des enregistrements

dbDenyRead

Interdit aux autres utilisateurs de lire les données d'une table

dbInconsistent

Autorise les mises à jour incohérentes

dbConsistent

Autorise uniquement les mises à jour cohérentes

Certaines constantes ont été volontairement oubliées dans cette liste du fait qu'elles sont soit inapplicables sous Access, soit déconseillées.

LockEdits : Il s'agit du mode de verrouillage des données utilisé par le Recordset.
Les constantes disponibles sont :

Constante

Verrouillage

dbReadOnly

Interdit aux utilisateurs d'apporter des modifications à l'objet Recordset

dbPessimistic

Utilise le verrouillage pessimiste afin de déterminer de quelle façon les modifications sont apportées à l'objet Recordset dans un environnement multi-utilisateur. La page contenant l'enregistrement que vous modifiez est verrouillée dès que vous utilisez la méthode Edit (option par défaut pour les espaces de travail Microsoft Jet).

dbOptimistic

Utilise le verrouillage optimiste afin de déterminer de quelle façon les modifications sont apportées à l'objet Recordset dans un environnement multi-utilisateur. La page contenant l'enregistrement n'est pas verrouillée tant que l'exécution de la méthode Update n'est pas terminée

Certaines constantes ont été volontairement oubliées dans cette liste du fait qu'elles sont inapplicables sous Access.

Exemple :

Dim oRst as DAO.Recordset
Dim oDb as DAO.Database
Set oDb=CurrentDb
Set oRst=oDb.OpenRecordset("SELECT * FROM Client WHERE NumClient=2",dbOpenDynaset)

Cet exemple ouvre un Recordset retournant le client possédant le numéro 2.

5-2-2 - Depuis un objet QueryDef

Si vous souhaitez accéder aux données d'une requête enregistrée vous pouvez utiliser la méthode OpenRecordset de l'objet QueryDef correspondant plutôt que d'utiliser celle de l'objet Database qui nécessite de passer en paramètre le nom de la requête.

La syntaxe de cette méthode est la suivante :

Set recordset = QueryDef.OpenRecordset ([type, options, lockedits])

Les arguments à utiliser sont les mêmes que ceux de la méthode Database.OpenRecordset. Notons toutefois qu'il est impossible d'ouvrir un Recordset de type Table sur un objet QueryDef.

Dans le cas d'une requete paramétrée, vous devez affecter les paramètres avant d'ouvrir le recordset. Il est impossible d'ouvrir un recordset sur une requete qui demande à l'utisateur de saisir des critères via une boite de dialogue (type inputbox). Une erreur d'éxecution ( X arguments attendus serait alors levée).

5-2-3 - Depuis un formulaire Access

Sans que vous le sachiez, vous avez déjà manipuler des objets Recordset par le biais d'un formulaire. En effet, tout formulaire (et état) Access possédant une source de données (Propriété Source / RecordSource) utilise un curseur pour afficher et manipuler les données qu'il contient. Vous pouvez vous même agir sur ce jeu d'enregistrement via la propriété Recordset du formulaire. Ainsi, si vous utilisez la méthode Movenext sur le Recordset du formulaire, vous vous apercevrez que votre formulaire a atteint l'enregistrement suivant. Notons aussi que tout déplacement dans le Recordset du formulaire entraine l'appel de l'evenement Form_Current (sur activation) du formulaire.

Syntaxe :

Set recordset=Me.Recordset

La méthode RecordsetClone d'un formulaire permet de dupliquer le jeu d'enregistrements du formulaire afin que vous puissiez manipuler les données sans que ces modifications ne soient répercutées sur le formulaire et sans qu'aucun évènement ne soit déclenché. Pour que le formulaire prenne en compte les modifications apportées sur le jeu d'enregistrements, il est nécessaire d'appeler la méthode Requery de ce formulaire.

Set recordset=Me.RecordsetClone

5-2-4 - Fermer un Recordset

Lorsque vous manipulez les recordsets, une quantité importante de données est chagée en mémoire. Pour la libérer il est nécessaire de procéder en deux temps :

1. appel de la méthode Recordset.Close,

2. affectation de Nothing à la variable.

Si la phase Set Recordset=Nothing est optionnelle car les variables seront inévitablement détruites à la fin de la procédure (hors variables publiques détruite en fin d'application), l'appel à Close à quant à lui un caractère obligatoire. En effet, une non fermeture systématique des Recordsets est à l'origine de l'accroissement si particulier de la taille des bases de données Access, obligeant l'utilisateur à recourrir au compactage régulièrement.

Une bonne pratique consiste à placer la ligne suivante dès qu'un recordset n'est plus utile :

oRst.Close : Set oRst=Nothing

5-3 - Positions et déplacements

5-3-1 - Se déplacer dans un Recordset

Lorsque vous initialisez un jeu d'enregistrements, l'enregistrement courant est le premier si le recordset n'est pas vide. Toutefois, il existe deux positions particulières :

- une avant le premier enregistrement. Lorsque vous êtes à cet emplacement, la propriété BOF du Recordset est égale à True

- une après le dernier enregistrement. Dans ce cas, la propriété EOF est égale à True.

Dans le cas où le jeu d'enregistrement est vide, la position courante se trouve à la fois avant le premier enregistrement et aprés le dernier. Ainsi, pour tester si le Recordset est vide ou pas, il suffit d'utiliser la condition suivante :

If Not oRecordset.EOF Then
Msgbox "Le jeu d'enregistrements n'est pas vide"
else
Msgbox "Le jeu d'enregistrements est vide"
End if

Cinq méthodes sont disponibles pour se déplacer dans le Recordset :

- MovePrevious permet d'atteindre l'enregistrement précédent.

- MoveNext permet d'atteindre l'enregistrement suivant.

- MoveFirst permet d'atteindre le premier enregistrement.

- MoveLast permet d'atteindre le dernier enregistrement.

- Move permet un déplacement relatif par rapport à la position courante..

Exemple :

'Se place sur le premier enregistrement
oRecordset.MoveFirst
'Se place sur le dernier enregistrement
oRecordset.MoveLast
'Se place sur l'enregistrement précédent
oRecordset.MovePrevious
'Se place sur l'enregistrement suivant
oRecordset.MoveNext
'Recule de trois enregistrements
oRecordset.Move -3
'Avance de trois enregistrements
oRecordset.Move 3

Lorsque vous atteignez le dernier enregistrement et que vous utilisez la méthode MoveNext, la propriété EOF est égale à True et la position courante n'est plus un enregistrement. Vous êtes à la fin du recordset et un nouveau déplacement vers l'avant entrainera une erreur d'exécution. (Il en va de même pour BOF et les déplacements en arrière)

Pour parcourir l'ensemble des enregistrements d'un Recordset, vous procéderez ainsi :

'Tant que non fin du recordset
While Not oRecordset.EOF
'Passer au suivant
oRecordset.MoveNext
Wend

5-3-2 - Trouver un enregistrement

Les méthodes dont le nom commence par Find permettent d'atteindre un enregistrement dont les données vérifient le critère passé en paramètre. Ce critère correspond à la clause WHERE d'une requête SQL.

La différence entre les diverses méthodes réside dans le sens de la recherche.

- FindNext recherche le prochain enregistrement (à partir de la position courante) vérifiant le critère.

- FindPrevious effectue la même recherche mais vers l'arrière.

- FindFirst trouve le premier enregistrement (à partir du début du jeu d'enregistrement) vérifiant le critère.

- FindLast trouve le dernier enregistrement (à partir de la fin du jeu d'enregistrement).

Ainsi, pour se positionner sur le premier enregistrement dont le champ NomClient commence par T dans un formulaire :

Dim strCritere as string
strCritere="NomClient LIKE " & chr(34) & "T*" & chr(34)
Me.Recordset.FindFirst strCritere

Si aucun enregistrement ne vérifie le critère, la propriété NoMatch du recordset est égale à True.

Exemple :

Dim strCritere as string
strCritere="NomClient LIKE " & chr(34) & "T*" & chr(34)
Me.Recordset.FindFirst strCritere
If Me.Recordset.NoMatch Then Msgbox "Aucun enregistrement n'a été trouvé"

5-3-3 - Mémoriser une position

Parfois, vous souhaitez naviguer dans le jeu d'enregistrements puis revenir à la position ou vous étiez avant. La propriété Bookmark du Recrodset retourne un signet vers l'enregistrement. Il s'agit d'un tableau contenant des données de type Byte.

Dim BytPosition() as Byte
BytPosition=oRecordset.Bookmark

Si par la suite, vous souhaitez revenir à cette position, il suffit d'affecter la valeur mémorisée à la propriété Bookmark.

oRecordset.Bookmark=BytPosition

5-4 - Manipulation des données

5-4-1 - Lire un enregistrement

Il est possible de lire les données de l'enregistrement courant à l'aide de la collection Fields. Cette collection fonctionne comme les autres collection DAO et il est possible d'appeler chaque élément par son nom ou par sa position dans la collection.

Dim oRst as DAO.Recordset
Dim oDb as DAO.Database
Set oDb=CurrentDb
Set oRst=oDb.OpenRecordset("SELECT NumClient,NomClient FROM Client WHERE NumClient=2",dbOpenDynaset)
Msgbox "Le nom du client est : " & Rst.Fields("NomClient").Value

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

Ou

Dim oRst as DAO.Recordset
Dim oDb as DAO.Database
Set oDb=CurrentDb
Set oRst=oDb.OpenRecordset("SELECT NumClient,NomClient FROM Client WHERE NumClient=2",dbOpenDynaset)
Msgbox "Le nom du client est : " & Rst.Fields(1).Value

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

La propriété Value est le membre par défaut d'un objet Field. Vous pouvez donc utiliser :

Msgbox "Le nom du client est : " & Rst.Fields(1)

5-4-2 - Modifier un enregistrement

La modification d'un enregistrement peut se décomposer en 4 étapes :

L'exemple suivant fixe la date de toutes les commandes à aujoud'hui.

Dim oRst as DAO.Recordset
Dim oDb as DAO.Database
Set oDb=CurrentDb
Set oRst=oDb.OpenRecordset("TblCommande",dbOpenTable)
While Not oRst.EOF
'Passe en mode modification
oRst.Edit
'Affecte la date actuelle
oRst.Fields("DateCommande").Value=Now()
'Met à Jour
oRst.Update
'Passe au suivant
oRst.MoveNext
Wend

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

Notre exemple réalise un Update massif sur l'ensemble de la table commande. Toutefois ne perdez pas de vue que dans bien des cas, une instruction SQL peut suffir et reste bien plus performante qu'une boucle sur un jeu d'enregistrement.

CurrentDb.Execute "UPDATE TblCommande SET DateCommande=#" & Now() & "#"

5-4-3 - Ajouter un enregistrement

La méthode AddNew d'un Recordset permet d'ajouter un enregistrement. Aprés avoir assigné les valeurs aux différents champ, vous devez faire appel à la méthode Update pour mettre à jour les données ou bien à la méthode CancelUpdate pour annuler l'ajout. L'enregistrement nouvellement créé est placé à la fin du jeu d'enregistrement, excepté dans le cas d'un Recordset de type Table où l'enregistrement est placé suivant l'ordre des index de la table. Dans tout les cas, le Recordset revient à sa position d'origine avant l'appel de la méthode Update.

Exemple :

Dim oRst as DAO.Recordset
Dim oDb as DAO.Database
Set oDb=CurrentDb
Set oRst=oDb.OpenRecordset("TblProduit",dbOpenTable)
'Passe en mode Ajout
oRst.AddNew
'Affecte les différents champs
oRst.Fields("Reference").Value="SRS200"
oRst.Fields("Libelle").Value="Souris optique sans fil"
'Met à Jour
oRst.Update

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

Vous devez affecter chacun des champs dont la propriété Required est égale à True, sans quoi une erreur sera levée. De même vous devez respecter les contraintes d'index que vous avez définit sur la table. Ainsi, une clé primaire ne peut contenir de doublons.

Dans le cas où un des champs est de type NuméroAuto, il est impossible d'affecter une valeur à ce champ. La numérotation automatique est gérée par le moteur Jet. Toutefois, pour des raisons diverses et variées, vous pouvez avoir le besoin de connaitre la nouvelle valeur du NuméroAuto créé. La valeur d'un tel champ est disponible avant l'appel de la méthode Update. Prenons l'exemple d'une table client dont le champ NumClient est auto-incrémenté :

Dim oRst as DAO.Recordset
Dim oDb as DAO.Database
Dim LngNouvelleValeur as Long
Set oDb=CurrentDb
Set oRst=oDb.OpenRecordset("TblClient",dbOpenTable)
'Passe en mode Ajout
oRst.AddNew
'Affecte les différents champs
oRst.Fields("NomClient").Value="DUPONT"
oRst.Fields("PrenomClient").Value="Martin"
'Récupère le nouvel identifiant
LngNouvelleValeur=oRst.Fields("NumClient").Value
'Met à Jour
oRst.Update
'Affiche le numéro client de
'l'enregistrement nouvellement créé
Msgbox "Le client " & NouvelleValeur & " a été créé"

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

Dans le cas d'un nombre important d'enregistrements à ajouter, un ordre SQL (INSERT) envoyé à la méthode Execute de l'objet Database sera plus performant que de charger un curseur contenant tous les enregistrements en mémoire.

Nous aurions donc avec l'exemple de la souris optique :

Dim StrChaineSQL As String
StrChaineSQL="INSERT INTO TblProduit (Reference,Libelle) VALUES (" & chr(34) & "SRS200" & chr(34) & _
"," & chr(34) & "Souris optique sans fil" & chr(34) & ")"
CurrentDb.Execute StrChaineSQL

Toutefois, avec cette syntaxe il est impossible de retrouver la valeur d'un champ NuméroAuto lors de l'ajout d'un enregistrement. Certains affirmeront qu'il suffit alors de récupérer la valeur maximum du champ concerné pour ne sélectionner que le dernier enregistrement de la table, toutefois, cela ne garantit pas qu'il s'agisse de l'enregistrement que vous venez d'ajouter. En effet, un autre utilisateur peut avoir ajouté un autre enregistrement immédiatement après vous.

5-4-4 - Supprimer un enregistrement

La méthode Delete d'un objet Recordset de type Table ou Dynaset permet de supprimer l'enregistrement courant. Aprés la suppression, l'enregistrement en cours n'est plus défini. Il est considéré comme supprimé et une erreur sera levée si vous tentez d'y accéder. Il vous faut donc modifier la position courante du curseur à l'aide des méthodes MoveNext ou MovePrevious.

L'exemple suivant supprimer toute les commandes du client numéro 13

Dim oDb as DAO.Database
Dim oRst as DAO.Recordset
'Instancie la base de données
Set oDb=CurrentDb
'Ouvre le curseur
Set oRst=oDb.OpenRecordset("SELECT * FROM TblCommandes WHERE NumClient=13")
'Parcours le jeu d'enregistrement jusqu'à la fin
While Not oRst.EOF
'Supprime l'enregistrement
oRst.Delete
'Passe au suivant
oRst.MoveNext
Wend

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

5-4-5 - Compter les enregistrements

Il existe deux façons de procéder pour compter le nombre d'enregistrements d'un Recordset.
La première consiste à utiliser une requete utilisant l'instruction SQL Count et de lire cette valeur.

Ainsi, le nombre de clients habitant à Paris peut être déterminé par :

Dim oDb as DAO.Database
Dim oRst as DAO.Recordset
Dim LngNbEnregistrement As Long
'Instancie la base de données
Set oDb=CurrentDb
'Ouvre le curseur retournant le nombre de clients résidant à Paris
Set oRst=oDb.OpenRecordset("SELECT Count(*) FROM TblCLients WHERE Ville=" & Chr(34) & "Paris" & Chr(34))
'Lit le résultat
LngNbEnregistrement=oRst.Fields(0).Value

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

Notons qu'une requête utilisant la fonction de regroupement Count retourne au moins un enregistrement. De ce fait le curseur ne sera jamais vide à son ouverture, il n'est donc pas obligatoire de tester l'existence d'enregistrement au sein du recordset avant de lire sa première ligne.

La seconde façon de procéder consiste à utiliser la propriété RecordCount du Recordset. Cette propriété renvoie le nombre d'enregistrements d'un recordset de type Table ou le nombre d'enregistrements accédés lorsqu'il s'agit d'un Recordset d'un autre type.

Ainsi, pour compter le nombre d'enregistrements d'un recordset de type table, nous pouvons utiliser :

Dim oDb as DAO.Database
Dim oRst as DAO.Recordset
Dim LngNbEnregistrement As Long
'Instancie la base de données
Set oDb=CurrentDb
'Ouvre le curseur retournant tous les clients
Set oRst=oDb.OpenRecordset("TblCLients",dbOpenTable)
'Compte les enregistrements
LngNbEnregistrement=oRst.RecordCount

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

Dans le cas d'un autre type de Recordset, nous devons utiliser MoveLast afin d'atteindre le dernier enregistrement. La propriété RecordCount retournera alors le nombre d'enregistrements de l'objet.

Dim oDb as DAO.Database
Dim oRst as DAO.Recordset
Dim LngNbEnregistrement As Long
'Instancie la base de données
Set oDb=CurrentDb
'Ouvre le curseur retournant le nombre de clients résidant à Paris
Set oRst=oDb.OpenRecordset("SELECT * FROM TblCLients WHERE Ville=" & Chr(34) & "Paris" & Chr(34),dbOpenDynaset)
'Atteint le dernier enregistrement
oRst.MoveLast
'Compte les enregistrements accédés (soit le total)
LngNbEnregistrement=oRst.RecordCount

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

5-4-6 - Filtrer les données

Il est possible d'ouvrir un nouvel objet Recordset depuis un premier Recordset tout en restreignant la selection des données à l'aide d'un filtre. Pour cela, vous devez spécifier un filtre à la propriété Filter du premier Recordset puis utiliser sa méthode OpenRecordset afin de retourner un nouveau jeu d'enregistrements filtré.

Le filtre à appliquer est une chaîne de caractères correspondant à la clause WHERE d'une requête (sans le WHERE).

Prenons comme exemple une table TblClients dont on ne sélectionne que les clients résidant à Paris.

Dim oDb as DAO.Database
Dim oRst as DAO.Recordset
Dim oRstFiltre as DAO.Recordset
'Instancie la base de données
Set oDb=CurrentDb
'Ouvre le curseur retournant tous les clients
Set oRst=oDb.OpenRecordset("SELECT * FROM TblClients",dbOpenDynaset)
'Applique le filtre de sélection des habitants de Paris
oRst.Filter="Ville=" & Chr(34) & "Paris" & Chr(34)
'Ouvre un nouveau curseur
Set oRstFiltre=oRst.OpenRecordset
'***************************************
'ici, traitement sur le recordset filtre
'***************************************

'Libération des objets
oRst.Close
oRstFiltre.Close
oDb.Close
Set oRst=Nothing
Set oRstFiltre=Nothing
Set oDb=Nothing

Notons toutefois que dans la majorité des cas, il est plus rapide d'ouvrir un nouvel objet Recordset directement depuis un objet Database en spécifiant une requête SQL complète à l'argument source.

Dim oDb as DAO.Database
Dim oRstFiltre as DAO.Recordset
'Instancie la base de données
Set oDb=CurrentDb
'Ouvre un curseur retournant tous les clients résidant à Paris
Set oRstFiltre=oDb.OpenRecordset("SELECT * FROM TblClients WHERE Ville=" & Chr(34) & "Paris" & Chr(34)",dbOpenDynaset)
'***************************************
'ici, traitement sur le recordset filtre
'***************************************

'Libération des objets
oRstFiltre.Close
oDb.Close
Set oRstFiltre=Nothing
Set oDb=Nothing

5-5 - Lecture par bloc

5-5-1 - Généralités

La lecture par bloc est un point trés important mais malheureusement fort oublié de DAO. En effet, la méthode GetRows permet de retourner un tableau possédant un nombre donné d'enregistrements. Ces enregistrements sont extraits à partir de la position courante du Recordset.

La syntaxe est la suivante :

Set varArray = recordset.GetRows (numrows)

VarArray est un tableau à deux dimensions recevant les données. Le premier indice correspond au champ et le second au numéro de l'enregistrement.

Recordset est le recordset possédant les données.

Numrows correspond au nombre d'enregistrements à lire.

Dans le cas où le nombre d'enregistrements disponibles est inférieur au nombre à extraire, la méthode GetRows retourne un tableau dont le nombre d'élément sera égal au nombre d'enregistrements disponibles. Il est donc conseillé d'utiliser la méthode UBound pour connaitre la borne supérieure du tableau.

Après extraction, la position courante du Recordset est définit sur l'enregistrement suivant le dernier lu, vous pouvez donc enchaîner une autre lecture vers l'avant. Dans le cas où vous souhaiteriez lire les X enregistrements précédents, il vous faut atteindre le premier enregistrement à lire à l'aide de l'instruction Move. (Sans toutefois atteindre la position BOF)

Lorsque le nombre de données à lire devient important, il s'avère que l'utilisation de la méthode GetRows pour accéder aux données représente un gain de rapidité pouvant atteindre 20 %.

5-5-2 - Exemple

Cet exemple met en oeuvre l'utilisation de la méthode GetRows afin de réaliser un formulaire affichant les enregistrements par blocs de 10. Les données proviennent de la table Clients de la base de données Comptoir.mdb (Répertoire samples d'Access). De cette table, nous conserverons uniquement les champs suivants :

Code Client, Société, Ville, Pays

Notre formulaire ce compose ainsi :

Chaque zone de texte est indépendante et possède un nom égal à celui de sa colonne, concaténé avec le numéro de l'enregistrement quelle affichera.

Nous utiliserons deux variables dans la portée du formulaire :

Dim oRstClient As DAO.Recordset  'Stocke le curseur
Dim intnbLus As Integer   'Stocke le nb d'enregistrements lus la dernière fois

Le principe est simple, à l'ouverture du formulaire, nous chargons le Recordset et affichons les 10 premiers enregistrements.

Private Sub Form_Load()
Dim oDb As DAO.Database
'Instancie la base de données
Set oDb = CurrentDb
'Ouvre le recordset
Set oRstClient = oDb.OpenRecordset("Clients", dbOpenTable)
'Lit les 10 premiers
LectureVersLAvant
End Sub

Private Sub LectureVersLAvant()
On Error GoTo err
RemplirZoneTexte oRstClient.GetRows(10)
Exit Sub
err:
'Si on est sur le dernier enregistrement
'alors ne rien faire, sinon avertir
If err.Number <> 3021 Then
MsgBox "Une erreur est survenue pendant la lecture des données", vbCritical, "Erreur"
End If
End Sub

La procédure RemplirZonetexte boucle sur chaque ligne du tableau et affiche la valeur du champ dans la zone de texte correspondante pour la ligne sélectionnée. Les autres lignes sont ensuites masquées.

Sub RemplirZoneTexte(Tableau As Variant)
Dim I As Integer
'Récupère le nombre d'enregistrements Lus
intnbLus = UBound(Tableau, 2) + 1
'affecte les valeurs aux zones de texte
For I = 0 To intnbLus - 1
'Affiche le code client
Controls("TCodeClient" & I + 1) = Tableau(0, I)
Controls("TCodeClient" & I + 1).Visible = True
'Affiche la societe
Controls("TSociete" & I + 1) = Tableau(1, I)
Controls("TSociete" & I + 1).Visible = True
'Affiche la ville
Controls("TVille" & I + 1) = Tableau(2, I)
Controls("TVille" & I + 1).Visible = True
'Affiche le pays
Controls("TPays" & I + 1) = Tableau(3, I)
Controls("TPays" & I + 1).Visible = True
Next I
'Masque les autres zones de textes
For I = intnbLus + 1 To 10
'Masque le code client
Controls("TCodeClient" & I).Visible = False
'Masque la societe
Controls("TSociete" & I).Visible = False
'Masque la ville
Controls("TVille" & I).Visible = False
'Masque le pays
Controls("TPays" & I).Visible = False
Next I
End Sub

Les déplacements vers l'arrière sont plus complexes étant donné que si nous avons lu les 20 premiers, la position courante du Recordset est définie à 21 et les enregistrements 11 à 20 sont affichés. Or, la plage souhaitée est celle des lignes 1 à 10. Nous devons donc reculer du nombre d'enregistrements lu la précédente fois et nous positionner 10 enregistrements en arrière pour commencer la lecture. Toutefois, il se peut que ce nombre de sauts excède le nombre d'enregistrements disponibles vers l'arrière. Le plus simple est alors d'intercepter l'erreur levée (3021) afin de ne pas stopper l'éxecution et de se positionner sur le premier enregistrement du curseur.

Private Sub LectureVersLArriere()
On Error GoTo err
'Recule du nombre d'enregistrements nécessaire
oRstClient.Move -1 * intnbLus - 10
RemplirZoneTexte oRstClient.GetRows(10)
Exit Sub
err:
Select Case err.Number
'Si on a trop reculé alors, se positionner sur le premier
Case 3021: oRstClient.MoveFirst
'Sinon, Avertir
Case Else: MsgBox "Une erreur est survenue pendant la lecture des données", vbCritical, "Erreur"
End Select
End Sub

Vous pouvez aisément obtenir une interface ressemblant à ceci :

Vous pouvez télecharger le fichier exemple ici.

5-6 - Liste des propriétés

Cette section récapitule l'ensemble des propriétés appliquables au Recordset DAO.

5-6-1 - AbsolutePosition

Type : Long

La propriété AbsolutePosition correspond à un numéro représentant la position courante dans le Recordset. Le premier enregistrement possède la position zéro. En affectant à cette propriété une valeur comprise entre 0 et le nombre d'enregistrements - 1, le curseur va se déplacer de telle sorte à atteindre l'enregistrement spécifié. Toutefois, privilégiez l'utilisation de la propriété Bookmark pour mémoriser une position et y retourner. Dans le cas où le jeu d'enregistrements est vide, cette propriété renvoie -1.

Elle ne s'applique pas aux Recorset de type Table (dbOpenTable) ni En avant seulement (dbOpenForwardOnly).

5-6-2 - BOF

Lecture seule.

Type : Boolean

Lorsque la propriété BOF d'un Recordset est égale à True, cela signifie que la position courante du curseur est définie avant le premier enregistrement.

Cette propriété s'applique à tous les types de Recordset.

5-6-3 - Bookmark

Type : Variant

La propriété Bookmark correspond à un signet identifiant de manière unique l'enregistrement au sein du Recordset. Cette propriété est à utiliser pour mémoriser une position ou se déplacer dans le jeu. Un exemple est disponible dans la section intitulée : 5.3.3 Mémoriser une position.

Cette propriété ne s'applique pas aux Recordset de type En avant seulement (dbOpenForwardOnly).

Les signets ne sont pas utilisables lorsque la propriété Bookmarkable est égale à False.

5-6-4 - Bookmarkable

Lecture seule.

Type : Variant

La propriété Bookmarkable renvoie True lorsque le curseur accepte les signets (Ce qui est automatiquement le cas pour une base de données Access). Si vous travailler en liaison avec certains SGBD, il est nécessaire de tester cette valeur avant d'utiliser la propriété Bookmark.

Cette propriété ne s'applique pas Recordset de type En avant seulement (dbOpenForwardOnly).

5-6-5 - CacheSize

Type : Long

La propriété CacheSize correspond au nombre d'enregistrements stockés en mémoire cache. Sa valeur doit être comprise entre 5 et 1200 sans dépasser la quantité de mémoire disponible. La valeur 0 désactive l'utilisation de la mémoire cache.

Cette propriété est utilisable uniquement avec les Recordset de type dynamique ou instantané et lorsque les données proviennent d'une source ODBC.

5-6-6 - CacheStart

Type : String

La valeur de la propriété CacheStart correspond au signet du premier enregistrement de l'objet Recordset à placer en mémoire cache. Vous pouvez utiliser le signet de tout enregistrement pour définir la propriété CacheStart.

Cette propriété est utilisable uniquement avec les Recordset de type dynamique ou instantané et lorsque les données proviennent d'une source ODBC.

Cette propriété étant très bien documentée dans l'aide, je vous renvoie vers cette dernière pour de plus amples détails

5-6-7 - Connection

Lecture seule.

Type : Connection

Dans un environnement ODBC Direct, la propriété Connection renvoie l'objet Connection depuis lequel le Recordset a été ouvert.

Cette propriété n'est pas disponible pour les curseurs de type Table.

5-6-8 - DataCreated

Lecture seule.

Type : Date

Pour un Recordset de type Table, cette propriété retourne la date de création de la table.

5-6-9 - EditMode

Lecture seule.

Type : Long

La propriété EditMode renvoie une valeur indiquant l'état de modification de l'enregistrement courant.

Il s'agit d'une des constantes suivantes :

Constante

Signification

dbEditNone

Aucune opération de modification en cours.

DbEditInProgress

La méthode Edit a été invoquée et l'enregistrement actuel est dans le tampon de copie. (La méthode Update n'a pas encore été appelée)

dbEditAdd

La méthode AddNew a été invoquée et l'enregistrement actuel dans le tampon de copie est un nouvel enregistrement qui n'a pas été enregistré dans la base de données.

Cette propriété s'applique à tous les types de Recordset.

Ainsi dans un code complexe, il est possible de connaitre le statut de votre Recordset. Ainsi, pour savoir si nous sommes sur le point de valider l'ajout d'un enregistrement, nous devrons évaluer :

If oRecordset.EditMode=dbEditAdd then Msgbox "Un ajout est en cours"

Toutefois, si votre code est bien structuré, vous devez être capable de connaitre le statut de votre curseur à chaque ligne de code. L'utilisation de cette propriété doit donc se limiter a des cas extrèmes, ou pour debugguer un code existant.

5-6-10 - EOF

Lecture seule.

Type : Boolean

Lorsque la propriété EOF d'un Recordset est égale à True, cela signifie que la position courante du curseur est définie après le dernier enregistrement.

Cette propriété s'applique à tous les types de Recordset.

5-6-11 - Fields

Lecture seule.

Type : Collection

Cette collection regroupe l'ensemble des champs du Recordset. De plus amples informations sur les objets Field sont disponibles dans la section 4.4 L'objet Field.

Cette propriété s'applique à tous les types de Recordset.

5-6-12 - Filter

Type : String

La propriété Filter permet de spécifier un filtre qui sera appliqué lors de l'appel de la méthode OpenRecordset. Il s'agit de la clause WHERE d'une requête SQL (sans le mot clé WHERE). De plus amples informations sont disponibles dans la section 5.4.6 Filtrer les données.

5-6-13 - Index

Type : String

La propriété Index correspond au nom de l'index utilisé dans un Recordset pour rechercher les enregistrements dans un Recordset de type Table exclusivement.

5-6-14 - LastModified

Lecture seule.

Type : Variant

Cette propriété retourne un signet pointant vers le dernier enregistrement modifié ou ajouté au jeu d'enregistrements. Vous pouvez atteindre ensuite cet enregistrement en affectant ce signet à la propriété Bookmark.

Exemple :

With oRecordset
.Bookmark=.LastModified
End With

Cette propriété s'applique à tous les types de Recordset hormis le type En avant seulement (dbOpenForwardOnly).

5-6-15 - LastUpdated

Lecture seule.

Type : Date

La propriété LastUpdated retourne la date à laquelle la table d'un Recordset a été modifiée pour la dernière fois.

Elle n'est appliquable qu'aux objets Recordset de type Table.

5-6-16 - LockEdits

Type : Boolean

Cette propriété définit le type de verrouillage utilisé par le Recordset. Lorsque'elle est égale à True (Valeur par défaut), la page est verrouillée dés l'appel de la méthode Edit. Dans le cas contraire (False), la page d'enregistrements est verrouillée uniquement lors de l'appel de la méthode Update.

5-6-17 - Name

Type : String

La propriété Name représente le nom de l'objet. Cette propriété est inutile dans l'utilisation des Recordset étant donné que ceux-ci ne sont pas nommés. Cette propriété est en fait égale aux 256 premiers caractères de l'argument Source utilisé lors de la méthode Database.OpenRecordset.

5-6-18 - NoMatch

Lecture seule.

Type : Boolean

La propriété NoMatch est égale à True lorsque l'une des méthodes Find.... n'a pas trouvé d'enregistrement vérifiant le critère.

5-6-19 - PercentPosition

Type : Single

La propriété PercentPosition correspond à une valeur 0 à 100 indiquant la position approximative dans le Recordset. Bien que vous puissiez la définir pour vous déplacer, elle est de faible intérêt en écriture car approximative.

Elle n'est appliquables qu'aux Recordset de type Table, Dynaset et instantané.

Vous devez avoir atteint le dernier enregistrement afin que sa valeur soit significative par rapport à la globalité du Recordset. Sinon, cette propriété ne se base pas sur le nombre d'enregistrements total mais parcourus. Pour atteindre le dernier enregistrement, vous pouvez utiliser la méthode MoveLast.

5-6-20 - Properties

Lecture seule.

Type : Collection

Cette collection regroupe l'ensemble des propriétés du Recordset, comme spécifié dans la section 4.2 Propriétés spécifiques.

5-6-21 - RecordCount

Lecture seule.

Type : Long

La propriété RecordCount retourne le nombre d'enregistrements total d'un Recordset de type Table ou le nombre d'enregistrements auxquels vous avez eu accès dans un Recordset d'un autre type.

Elle n'est pas appliquable aux Recordset de type En avant seulement (dbOpenForwardOnly)

De plus amples informations sur cette propriété sont disponible dans la section intitulée 5.4.5 Compter les enregistrements

5-6-22 - Restartable

Lecture seule.

Type : Long

Lorsque cette propriété est égale à True, cela signifie qu'il est possible de mettre les données à jour en réexécutant la requête à l'aide de Requery. En d'autres thermes, elle indique si la méthode Requery est supportée par le Recordset. Dans le cas contraire, vous devrez réouvrir le curseur à l'aide de la méthode OpenRecordset de l'objet Database ou QueryDef utilisé pour y puiser les données.

Elle est utilisable sur tout type de Recordset, toutefois, elle renvoie toujours False pour un Recordset de type Table.

5-6-23 - Sort

Type : String

La propriété Sort permet de spécifier un ordre de tri qui sera appliqué lors de l'appel de la méthode OpenRecordset. Il s'agit de la clause ORDER BY d'une requête SQL (sans le mot clé ORDER BY). Ainsi, il est possible d'instancier un nouvel objet Recordset trié depuis un autre :

Dim oDb as DAO.Database
Dim oRst as DAO.Recordset
Dim oRstTrie as DAO.Recordset
'Instancie la base de données
Set oDb=CurrentDb
'Ouvre le curseur retournant tous les clients
Set oRst=oDb.OpenRecordset("SELECT Ville,NomClient,PrenomClient FROM TblClients" _
,dbOpenDynaset)
'Tri sur la ville et le nom du client
oRst.Sort="Ville,NomClient"
'Ouvre un nouveau curseur
Set oRstTrie=oRst.OpenRecordset
'*************************************
'ici, traitement sur le recordset trié
'*************************************

'Libération des objets
oRst.Close
oRstTrie.Close
oDb.Close
Set oRst=Nothing
Set oRstTrie=Nothing
Set oDb=Nothing

Cette propriété ne s'applique qu'aux Recordset de type Dynaset et Instantané.

Notons toutefois que dans la majorité des cas, il est plus rapide d'ouvrir un nouvel objet Recordset directement depuis un objet Database en spécifiant une requête SQL complète à l'argument source.

5-6-24 - StillExecuting

Lecture seule.

Type : Boolean

Dans un environnement ODBC Direct, la propriété StillExecuting renvoie True si la requête d'ouverture du Recordset est encore en cours d'exécution.

5-6-25 - Transactions

Lecture seule.

Type : Boolean

Lorsque la propriété Transactions d'un objet Recordset est égale à True, cela signifie que vous pouvez utiliser les transactions sur ce Recordset. Pour démarrer une transaction, utilisez la méthode BeginTrans de l'objet Workspace ayant créer le curseur. Invoquez ensuite la méthode CommitTrans pour mettre à jour les données ou Rollback pour annuler.

Exemple :

Dim oRst as DAO.Recordset
Dim oDb as DAO.Database
Set oDb=CurrentDb
Set oRst=oDb.OpenRecordset("TblCommande",dbOpenTable)
'Demarre la transaction
DBEngine.Workspaces(0).BeginTrans
While Not oRst.EOF
'Passe en mode modification
oRst.Edit
'Affecte la date actuelle
oRst.Fields("DateCommande").Value=Now()
'Met à Jour
oRst.Update
'Passe au suivant
oRst.MoveNext
Wend
'Demande confirmation
If Msgbox("Etes vous sûr de vouloir continuer")=VbYes
'Si oui, mettre à jour
DBEngine.Workspaces(0).CommitTrans
Else
'Sinon, annuler
DBEngine.Workspaces(0).Rollback
End if

'Libération des objets
oRst.Close
oDb.Close
Set oRst=Nothing
Set oDb=Nothing

5-6-26 - Type

Lecture seule.

Type : Long

La propriété Type renvoie le type de curseur utilisé conformément aux informations spécifiées dans la section : 5.2 Les différents types de Recordset.

5-6-27 - Updatable

Lecture seule.

Type : Boolean

Lorsque la propriété Updatable est égale à False, il est impossible de mettre à jour les données du Recordset.

5-6-28 - UpdateOptions

Type : Long

La propriété UpdateOptions correspond au mode de création d'une clause WHERE dans une requête UPDATE lors d'une mise à jour par lot dans un environement ODBC Direct. Dans certains cas, il est ainsi possible de contourner un déclencheur Update du SGBD distant en forçant le moteur de base de données à remplacer une requête UPDATE par une requête DELETE suivie d'une requête INSERT. Toutefois, cette propriété ne sera pas d'avantage documentée dans ce document et je vous propose de consulter l'aide Access pour plus de détails.

5-6-29 - ValidationRule

Lecture seule.

Type : String

La propriété ValidationRule définit la règle de validation qui sera utilisée pour valider les données lors de l'appel de la méthode Update.

5-6-30 - ValidationText

Lecture seule.

Type : String

La propriété ValidationText correspond au message qui sera affiché lors d'une mise à jour si les données ne vérifie pas la règle spécifiée dans ValidationRule.

5-7 - Liste des méthodes

Voici un récapitulatif des méthodes de la classe Recordset.

5-7-1 - AddNew

La méthode AddNew permet d'ajouter un nouvel enregistrement au Recordset. Elle est illustrée dans la section 5.4.3 Ajouter un enregistrement.

Exemple :

With oRecordset
.AddNew
.Fields("Nom")="Toto"
.Update
End With

5-7-2 - CancelUpdate

La méthode CancelUpdate est à invoquer après les méthodes Edit ou Addnew pour annuler la mise à jour. Dans le cas d'un ajout, la position du Recordset est redéfinie à ce qu'elle était avant l'appel de AddNew.

Exemple :

With oRecordset
.AddNew
.Fields("Nom")="Toto"
'Annule l'insertion
.CancelUpdate
End With

5-7-3 - Clone

La méthode Clone retourne un Recordset identique à celui sur lequel elle est appliquée. Le recordset cloné ne possède pas d'enregistrement courant vous devez alors vous positionner sur l'enregistrement de votre choix. Notons que les signets sont interchangeables entre chaque Recordset. Ainsi, il est possible de positionner le clone au même endroit que la source avec :

Dim oRst as DAO.Recordset
Dim oRstClone as DAO.Recordset
'****************************
'ici Code d'ouverture de Rst
'****************************

'Copie du recordset
Set oRstClone=oRst.Clone
'Définit le même enregistrement courant
oRstClone.Bookmark=oRst.Bookmark

Une fois oRst cloné, vous pouvez le fermer sans aucune incidence sur RstClone.

Cette méthode n'est pas compatible avec les objets Recordset de type En avant seulement (dbOpenForwardOnly)

5-7-4 - Close

La méthode Close ferme le Recordset. Toutefois, celle-ci ne libère pas la variable objet de la mémoire. Pour la libérer, vous devez attendre la fin de la procédure et la destruction de la variable ou affecter Nothing à cette dernière.

Exemple :

oRecordset.Close
Set oRecordset=Nothing

5-7-5 - CreateQueryDef

La méthode CreateQueryDef copie l'objet QueryDef utilisé pour ouvrir le Recordset. Celui-ci doit impérativement avoir été ouvert à l'aide de la méthode OpenRecordset d'un objet QueryDef.

Syntaxe :

Set querydef = oRecordset.CopyQueryDef

Cette méthode ne s'applique pas aux Recordset de type Table (Puisqu'ils ne sont pas ouverts depuis un objet QueryDef).

5-7-6 - Delete

La méthode Delete supprime un enregistrement du Recordset. Elle est illustrée dans la section 5.4.4 Supprimer un enregistrement. Une fois l'enregistrement supprimé, la position du Recordset n'est plus valide, vous devez donc atteindre un autre enregistrement.

Exemple :

With oRecordset
.Delete
Msgbox "Suppression réussie"
.MoveNext
End With

5-7-7 - Edit

La méthode Edit copie l'enregistrement dans le tampon et passe le Recordset en mode acEditInProgress afin que vous puissiez modifier les données.

Un exemple d'utilisation est disponible dans la section : 5.4.2 Modifier un enregistrement.

5-7-8 - FindFirst, FindLast, FindNext, FindPrevious

Ces méthodes sont à utiliser pour trouver des enregistrements au sein du jeu. Une section complète leur est dédiée : 5.3.2 Trouver un enregistrement.

Elles ne sont disponibles que pour les Recordset de type Dynaset et Instantané.

5-7-9 - GetRows

La méthode GetRows lit et retourne dans un tableau à deux dimensions X enregistrements à partir de l'enregistrement courant (X étant un nombre positif spécifié dans le seul argument de GetRows). Un exemple de formulaire lisant les données par bloc est disponible dans la section 5.5 Lecture par bloc.

5-7-10 - Move, MoveFirst, MoveLast, MoveNext, MovePrevious

Ces méthodes sont à utiliser pour se déplacer au sein du jeu d'enregistrements comme indiqué dans la section 5.3.1 Se déplacer dans un Recordset.

Elles sont disponibles pour tout type de Recordset hormis les méthodes MoveFirst et MovePrevious qui opèrent des déplacements vers l'arrière et qui sont donc incompatibles avec les curseurs de type En avant seulement (dbOpenForwardOnly).

5-7-11 - OpenRecordset

La méthode OpenRecordset instancie un nouvel objet Recordset possédant la même source de données que le Recordset original mais en tenant compte des éventuelles propriétés Filter et Sort.

Voici un exemple d'utilisation appliquant un filtre :

Dim oDb as DAO.Database
Dim oRst as DAO.Recordset
Dim oRstFiltre as DAO.Recordset
'Instancie la base de données
Set oDb=CurrentDb
'Ouvre le curseur retournant tous les clients
Set oRst=oDb.OpenRecordset("SELECT * FROM TblClients",dbOpenDynaset)
'Applique le filtre de sélection des habitants de Paris
oRst.Filter="Ville=" & Chr(34) & "Paris" & Chr(34)
'Ouvre un nouveau curseur
Set oRstFiltre=oRst.OpenRecordset
'***************************************
'ici, traitement sur le recordset filtre
'***************************************

Cette méthode n'est pas disponible pour les Recordset de type En avant seulement (dbOpenForwardOnly).

5-7-12 - Requery

La méthode Requery met à jour les données contenues dans un objet Recordset en exécutant de nouveau la requête sur laquelle l'objet est fondé.

Notons que certains SGBD ne supportent pas l'utilisation de la méthode Requery. Dans ce cas, vous pouvez interroger la propriété Restartable afin de connaître si Requery est applicable.

5-7-13 - Update

La méthode Update permet d'enregistrer les données depuis le tampon de copie vers la base de données. Cette méthode est à invoquer aprés l'affectation des différents champs suite à un appel à la méthode Edit ou AddNew. Pour ne pas enregistrer les données, vous devez utiliser la méthode CancelUpdate.

Pour de plus amples informations, vous pouvez consulter la section 5.4.2 Modifier un enregistrement.

6 - Conclusion

Tout au long de ce document, vous avez pu constater que DAO offre de multiples possibilités quant à la manipulation d'une base de données. Toutefois, chaque action doit être réfléchie et en aucun cas vous ne devez perdre de vue que la cohérence et l'intégrité des données sont primordiales. A aucun moment vous ne devez prendre le risque de perdre des enregistrements.

Depuis quelques années, DAO tente à être remplacé par le modèle objet ADO (ActiveX Data Object). Cependant, il reste un moyen simple d'accéder à votre base de données dans du code VBA. La hiérarchie du modèle DAO étant très proche de la fenêtre base de données sous Access, son approche est très intuitive et ne nécessite pas de réelles connaissances dans le monde de la programmation orientée objet.

Je tiens à remercier l'ensemble de l'équipe Access pour ses précieux conseils et sa relecture ainsi que MED ALAOUI SOSSE pour sa traduction en arabe. Je reste à votre disposition par MP pour d'éventuelles remarques.