IX. L'objet Table▲
Cet objet représente une table de la base de données. Les tables de type « VIEW » seront vues dans le chapitre du même nom. Nous allons donc regarder les tables Standard.
Une table contient des champs (colonnes), des index, des clés et des propriétés propres au fournisseur.
Seules deux propriétés intéressantes sont statiques : « Name » qui représente le nom de la table et est obligatoire, et « type » qui porte bien son nom, mais qui est en lecture seule. Ceci fait qu'il n'y a pas de questions existentielles à se poser, lorsqu'on crée une table avec ADOX, elle est forcément standard.
La table n'existe réellement dans la base de données que lorsque
- Son catalogue est défini
- Elle est ajoutée à la collection Tables.
Il convient donc de créer entièrement la table avant de l'ajouter à la collection.
IX-A. Collection Properties▲
Cette collection n'est utilisée que dans le cas des tables liées. N'essayez pas de créer des tables liées en partant du catalogue de votre base, bien que techniquement possible cela n'est pas conseillé. Le code suivant crée une table liée
Sub
CreateAttachedJetTable
(
)
Dim
Catalogue As
ADOX.Catalog
, MaTable As
ADOX.Table
Set
Catalogue =
New
ADOX.Catalog
Catalogue.ActiveConnection
=
"Provider=Microsoft.Jet.OLEDB.4.0;"
&
"Data Source=D:\ADOX\baseheb.mdb;Jet OLEDB:System database="
&
"D:\ADOX\system.mdw;User Id=Admin; Password="
Set
MaTable =
New
ADOX.Table
MaTable.Name
=
"auteurs"
Set
MaTable.ParentCatalog
=
Catalogue
MaTable.Properties
(
"Jet OLEDB:Create Link"
) =
True
MaTable.Properties
(
"Jet OLEDB:Link Datasource"
) =
"D:\adox\Biblio.mdb"
MaTable.Properties
(
"Jet OLEDB:Link Provider String"
) =
";Pwd=password"
MaTable.Properties
(
"Jet OLEDB:Remote Table Name"
) =
"auteurs"
Catalogue.Tables.Append
MaTable
Set
Catalogue =
Nothing
End
Sub
Lorsque j'écris que c'est déconseillé, ce n'est pas dû à la complexité du code, mais pour les deux raisons suivantes :
- Il faut s'assurer que le fournisseur utilisé pour faire la liaison sera présent sur le poste qui exécute.
- Il faut bien savoir si les paramètres de sécurité de liaison seront ou ne seront pas stockés de façon permanente dans la base.
Regardons ce code. Après avoir défini un catalogue, nous créons un objet Table. Dans cet exemple, le nom est le même que le vrai nom de la table dans l'autre base, mais cela n'a aucune importance. Ensuite je lui attribue un catalogue afin de pouvoir valoriser ses propriétés dynamiques. Notez bien que j'utilise l'objet Catalog de ma base, car je crée une table liée dans ma base.
Je valorise ensuite mes propriétés dynamiques, notons que je ne mets pas de fournisseur dans « Jet OLEDB:Link Provider String », car je continue d'utiliser Jet, mais je pourrais tout à fait changer le fournisseur. Enfin j'ajoute ma table à la collection. À partir de cet ajout, la table liée est créée, mais un certain nombre de ses propriétés sont passées en lecture seule.
IX-B. Collection Columns▲
Il existe des collections/objets Column pour l'objet Table, Index et Key. Attention de ne pas les confondre.
La collection Columns regroupe les champs de la table. Elle possède les propriétés/méthodes d'une collection normale.
Append (méth.) : De la forme
Columns.Append Column [, Type] [, DefinedSize]
Où Column est l'objet colonne à ajouter.
IX-B-1. Objet Column▲
Représente dans ce cas un champ de la table. À ne pas confondre avec l'objet Column de l'index. Cet objet n'a pas de méthode.
Propriétés▲
Attributes
Définit si la colonne est de longueur fixe et si elle accepte les valeurs NULL.
DefinedSize
Définit la taille maximum du champ
Name
Nom de la table. Obligatoire. L'unicité d'un nom dans une collection n'est pas obligatoire, mais dans une même base, il ne peut pas y avoir deux tables portant le même nom.
NumericScale
À ne pas confondre avec la propriété Précision. Donne l'échelle (nombre de chiffres après la virgule) d'un champ dont le type est adNumeric ou adDecimal.
ParentCatalog
Qu'on ne présente plus !
Precision
Définit la précision (nombre maximal de chiffres pour représenter la valeur) d'un champ numérique.
Type
Définit le type du champ. Il existe beaucoup de types définis (39), mais le tableau suivant vous donnera les principaux types Access.
Type |
Valeur |
Commentaire |
---|---|---|
adSmallInt |
2 |
Type Entier court |
adInteger |
3 |
Type Entier long (Access) |
adSingle |
4 |
Valeur décimale à simple précision |
adDouble |
5 |
Valeur décimale à double précision |
adCurrency |
6 |
Type monétaire. Utilise normalement 4 chiffres après la virgule |
adDate |
7 |
Stocké comme un double. La partie entière étant le nombre de jours depuis le 30/12/1899 |
adBoolean |
11 |
Booléen |
adUnsignedTinyInt |
17 |
Numérique de type Octet |
adGUID |
72 |
Par exemple numéro de réplication |
adVarWChar |
202 |
Chaîne de caractères (type Text Access) |
adLongVarWChar |
203 |
Champs mémo (Access) et lien hypertexte |
adLongVarBinary |
205 |
Type OLE Object Access |
Collection Properties▲
Les propriétés dynamiques de l'objet Column intéressantes sont :
Autoincrement : Permet de créer les colonnes à numérotation automatique.
Default : Définit la valeur par défaut d'un champ.
Nullable : Définit si la colonne accepte des valeurs NULL.
Fixed Length : Définit si la colonne est de longueur fixe.
Seed : Détermine la prochaine valeur qui sera fournie par un champ de type numéro Automatique.
Increment : Définit le pas d'incrément d'un champ NuméroAuto.
Jet OLEDB:Column Validation Text : Définit le message d'alerte si une règle de validation n'est pas respectée.
Jet OLEDB:Column Validation Rule : Définit une règle de validation pour un champ.
Jet OLEDB:Allow Zero Length : Définit si les chaînes vides sont autorisées.
Exemple▲
Dans l'exemple suivant, nous allons créer une table contenant trois champs, Identification de type NuméroAuto, Nom de type Texte, Ntel de type numérique formaté.
Dim
Catalogue As
ADOX.Catalog
, MaTable As
ADOX.Table
Dim
strConn As
String
, compteur As
Long
, MaCol As
ADOX.Column
Set
Catalogue =
New
ADOX.Catalog
strConn =
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
&
"D:\User\jmarc\tutorial\ADOX\Test\NouvBase1.mdb"
Catalogue.Create
strConn
Set
MaTable =
New
ADOX.Table
MaTable.Name
=
"PremTable"
For
compteur =
1
To
3
Set
MaCol =
New
ADOX.Column
With
MaCol
.DefinedSize
=
Choose
(
compteur, 0
, 50
, 14
)
.Name
=
Choose
(
compteur, "Id"
, "Nom"
, "Tel"
)
.Type
=
Choose
(
compteur, adInteger
, adVarWChar
, adVarWChar
)
.Attributes
=
Choose
(
compteur, 0
, adColFixed, adColFixed +
adColNullable)
If
compteur =
1
Then
Set
.ParentCatalog
=
Catalogue
MaCol.Properties
(
"Autoincrement"
) =
True
MaCol.Properties
(
"Seed"
) =
CLng
(
1
)
MaCol.Properties
(
"Increment"
) =
CLng
(
1
)
End
If
End
With
MaTable.Columns.Append
MaCol
Set
MaCol=
Nothing
Next
compteur
Catalogue.Tables.Append
MaTable
End
Sub
Je commence donc par créer la base de données. Pour cela j'utilise une chaîne de connexion qui est obligatoire pour pouvoir utiliser la méthode Create de catalogue. Dans cet exemple, je ne définis pas de fichier de sécurité. Ensuite je crée mon objet Table. Comme je n'utilise pas sa collection Properties, je ne valorise pas sa propriété ParentCatalog.
Dans la boucle, je crée mes colonnes. J'utilise la fonction Choose afin d'écrire de façon plus concise. Pour chaque colonne je définis une taille, un nom, un type et éventuellement ses attributs. Notons que comme la colonne n'est pas encore ajoutée à la collection Columns, elle n'existe pas encore. Dès lors, l'ordre de valorisation des propriétés n'a aucune importance. Dans le cas de la colonne « Id », je vais créer un champ NuméroAuto. Pour cela, je dois valoriser des propriétés dynamiques, donc je dois définir la propriété ParentCatalog. Enfin j'ajoute la colonne à la collection Columns puis la table à la collection Tables.
Notez aussi que tout ce code revient au même, à l'exception de la création de la base que la commande DDL
CREATE
TABLE
PremTable(
Id COUNTER, Nom TEXT
50
NOT
NULL
, Tel TEXT
14
)
IX-C. Collection Indexes▲
Représente les index de la table. Faites bien attention à ne pas confondre index et clé. Un index sert à augmenter l'efficacité du SGBDR lors des recherches, de la mise en relation etc..
Normalement devrait toujours être indexés
- Les colonnes composantes d'une clé
- Les colonnes ayant des contraintes de validité ou d'unicité
- Les colonnes étant la cible de nombreuses recherches.
Les propriétés/méthodes de cette collection sont celles des collections standard si ce n'est :
Append
De la forme : Indexes.Append Index [, Columns]
Où Columns renvoie le ou les noms des colonnes devant être indexées. En général, on définit l'objet colonnes avant son ajout à la collection
IX-C-1. Objet Index▲
Cet objet n'a pas de méthodes.
Attention, on ne peut utiliser un objet Column avec cet objet que si la colonne appartient déjà à la collection Columns de l'objet Table.
Clustered▲
Indique si l'index est regroupé. Un index regroupé signifie qu'il existe un ordre physique pour les données. C'est en général l'index de la clé primaire.
IndexNulls▲
Définit le comportement de l'index vis-à-vis des colonnes ayant une valeur NULL.
PrimaryKey▲
Précise si l'index représente la clé primaire de la table.
N. B. C'est là que je vous disais de faire attention. Une clé primaire (ou non d'ailleurs) est définie par la collection Keys. Néanmoins on définit en général aussi un index sur la colonne de clé primaire. En mettant à vrai cette propriété, la création de l'index implique la création de la clé. Donc si vous créez une clé primaire de façon implicite, n'essayez pas de la recréer après dans la collection Keys et vice versa.
Unique▲
Définit la contrainte d'unicité.
Collection Properties▲
Comme toujours, la propriété ParentCatalog de l'index doit être valorisée avant l'appel d'un membre de cette collection. La plupart de ces propriétés étant en lecture seule ou redondante avec les propriétés statiques de l'objet, nous n'irons pas plus avant dans notre exploration.
Collection Columns et objet Column▲
Définit les colonnes sur lesquelles porte l'index. N'oubliez pas qu'un index porte sur un ou plusieurs champs, mais qu'il appartient à l'objet Table.
L'objet Column doit impérativement exister dans la table avant de pouvoir être ajouté à la collection Columns de l'index.
Les colonnes des index utilisent une propriété supplémentaire
SortOrder▲
Définit l'ordre de tri d'une colonne d'index.
Exemple▲
Dans mon exemple précédent, je vais rajouter un index sur la colonne Nom, avec un tri croissant.
Set
MonIndex =
New
ADOX.Index
With
MonIndex
.IndexNulls
=
adIndexNullsDisallow
.Name
=
"ind1"
.Columns.Append
"Nom"
.Columns
(
"Nom"
).SortOrder
=
adSortAscending
End
With
MaTable.Indexes.Append
MonIndex
Ce code se situe après l'ajout des colonnes à l'objet Tables, mais avant l'ajout de l'objet Table. Comme précédemment, je manipule mon objet avant son ajout à la collection.
Seules les colonnes indexées supportent l'emploi de la méthode de recherche Seek du recordset ADO. Celle-ci est beaucoup plus performante que la méthode Find.
IX-D. Collection Keys▲
Nous allons aborder maintenant un des passages un peu « sensibles » de la programmation ADOX, c'est-à-dire les clés. Les clés sont le fondement de l'intégrité référentielle il convient de bien connaître le sujet avant de se lancer dans leur programmation. Normalement, vous avez travaillé sur le modèle de données avant de construire votre base donc il suffira de suivre celui-ci.
IX-D-1. Quelques notions▲
Les clés sont parfois appelées, improprement d'ailleurs, contraintes. Ceci vient du fait qu'en SQL, Primary Key est une contrainte. Pourtant si les clés peuvent être des contraintes, toutes les contraintes ne sont pas des clés.
Clé primaire▲
Cette clé devrait être composée d'une seule colonne, mais ce n'est pas une obligation. Elle sert à identifier chaque enregistrement de manière unique. La clé primaire n'accepte pas les valeurs NULL. Beaucoup de gens utilisent un champ à numérotation automatique pour définir la clé primaire, cela n'est en rien obligatoire. Une table n'a qu'une clé primaire.
Clé étrangère▲
Champ de même type/sous-type de données que la clé primaire, qu'elle référence dans la table enfant. Une table peut posséder plusieurs clés étrangères.
Intégrité référentielle▲
Mécanisme de vérification qui s'assure que, pour chaque valeur de clé étrangère, il y a une valeur de clé primaire lui correspondant. Ce mécanisme se déclenche lors de l'ajout d'une nouvelle valeur de clé étrangère, lors de la suppression d'une clé primaire ou lors de la modification de l'une quelconque des deux clés.
Opération en cascade▲
Mode opératoire dépendant de l'intégrité référentielle. Celui-ci détermine éventuellement le comportement du SGBDR en cas de suppression/modification d'un enregistrement parent.
IX-D-2. Méthode Append▲
De la forme Keys.Append Key [, KeyType] [, Column] [, RelatedTable]
Nous examinerons plus tard le détail des paramètres (dans les propriétés de l'objet Key).
IX-D-3. Objet Key▲
Représente une clé primaire, étrangère ou unique.
DeleteRule▲
Définit les règles à appliquer lors de la suppression d'une valeur de la clé primaire. On distingue 4 cas :
AdRINone
Aucune action (équivalent du mode de gestion SQL ON DELETE NO ACTION). Cette valeur interdit toute suppression d'un enregistrement tant qu'il existe un enregistrement dépendant dans la base.
AdRICascade
Modifications en cascade (SQL ON DELETE CASCADE). Attention à l'utilisation de cette valeur. Elle supprime tous les enregistrements liés lors de la suppression de l'enregistrement père. Ceci peut être très coûteux pour le SGBD en termes de performances et doit être limité au sein d'une transaction
AdRISetNull et adRISetDefault
Attribue la valeur nulle ou la valeur par défaut à la clé étrangère. Ceci se justifie rarement sauf pour gérer des traitements par lots a posteriori.
Name▲
Tel que son nom l'indique
RelatedTable▲
Si la clé est une clé étrangère, définit le nom de la table contenant la clé primaire correspondante.
Type▲
Détermine s'il s'agit d'une clé primaire, étrangère ou unique. Une clé unique est une clé sans doublons.
UpdateRule▲
Équivalent pour les modifications à DeleteRule pour les mises à jour.
Attention de nombreux SGBDR n'acceptent pas toutes les règles de modification/suppression. Je vous rappelle aussi que ces règles s'appliquent sur la clé étrangère ; les définir pour la clé primaire ne sert à rien.
Collection Columns et objet Column▲
Définit la ou les colonne(s) appartenant à la clé. Celles-ci doivent déjà appartenir à la collection Columns de l'objet Table. L'objet Column de l'objet Key utilise la propriété RelatedColumn. Celle-ci définit la colonne en relation dans la table définie par RelatedTable.
IX-D-4. Exemple▲
Nous allons voir maintenant un exemple de création de clé.
Dim
Catalogue As
ADOX.Catalog
, MaTable As
ADOX.Table
, compteur As
Long
Dim
MaCol As
ADOX.Column
, MaCle As
ADOX.Key
, MonIndex As
ADOX.Index
Set
Catalogue =
New
ADOX.Catalog
'ici se trouve le code précédemment vu
Set
MaCle =
New
ADOX.Key
With
MaCle
.Type
=
adKeyPrimary
.Name
=
"ClePrim"
.Columns.Append
"Id"
End
With
MaTable.Keys.Append
MaCle
Set
MaCle =
Nothing
Catalogue.Tables.Append
MaTable
Set
MaTable =
New
ADOX.Table
MaTable.Name
=
"DeuxTable"
For
compteur =
1
To
3
Set
MaCol =
New
ADOX.Column
With
MaCol
.DefinedSize
=
Choose
(
compteur, 0
, 255
, 0
)
.Name
=
Choose
(
compteur, "NumCle"
, "Local"
, "Responsable"
)
.Type
=
Choose
(
compteur, adInteger
, adVarWChar
, adInteger
)
Set
.ParentCatalog
=
Catalogue
.Attributes
=
Choose
(
compteur, 0
, adColFixed, 0
)
End
With
MaTable.Columns.Append
MaCol
Set
MaCol =
Nothing
Next
compteur
For
compteur =
1
To
2
Set
MonIndex =
New
ADOX.Index
With
MonIndex
.PrimaryKey
=
Choose
(
compteur, True
, False
)
.Unique
=
Choose
(
compteur, True
, False
)
.IndexNulls
=
adIndexNullsDisallow
.Name
=
Choose
(
compteur, "ind21"
, "Ind22"
)
.Columns.Append
Choose
(
compteur, "NumCle"
, "Responsable"
)
.Columns
(
Choose
(
compteur, "NumCle"
, "Responsable"
)).SortOrder
=
adSortAscending
End
With
MaTable.Indexes.Append
MonIndex
Set
MonIndex =
Nothing
Next
compteur
Set
MaCle =
Nothing
Set
MaCle =
New
ADOX.Key
With
MaCle
.DeleteRule
=
adRINone
.UpdateRule
=
adRINone
.Type
=
adKeyForeign
.Name
=
"CleEtr1"
.RelatedTable
=
"PremTable"
.Columns.Append
"Responsable"
.Columns
(
"Responsable"
).RelatedColumn
=
"Id"
End
With
MaTable.Keys.Append
MaCle
Set
MaCle =
Nothing
Catalogue.Tables.Append
MaTable
End
Sub
Dans ma première table, je crée une clé primaire de façon explicite. Je lui donne des règles NO ACTION. Je crée ensuite une deuxième table contenant trois champs. Le champ « NumCle » quoique n'étant pas de type NuméroAuto, doit être unique et non NULL. Le champ « Responsable » est la clé étrangère et contient la valeur du champ « Id » correspondant. Ces deux colonnes sont indexées. En jouant sur la propriété PrimaryKey de l'index, je crée implicitement la clé primaire en créant l'index. Notons que cette clé portera le même nom que l'index. Je crée ensuite ma clé étrangère et me voilà avec deux tables mises en relation.
IX-E. Conclusion sur les tables▲
Comme nous l'avons vu au cours de ce chapitre, le schéma de construction est assez simple. Voici les quelques règles à se rappeler :
- On crée les tables les unes après les autres en commençant toujours par les tables parents (celles qui n'ont pas de clés étrangères)
- On ajoute un objet à sa collection lorsqu'on l'a entièrement défini.
- On crée les champs de la table avant de définir les index et les clés.
- On indexe toujours les champs intervenant dans les jointures et/ou cible de recherche.
- La définition des clés lors de la création de la base augmente la sécurité des données.