[Résolu par voie détournée] Piloter des contraintes d'intégrité

Piloter des contraintes d'intégrité [Résolu par voie détournée] - VB/VBA/VBS - Programmation

Marsh Posté le 19-07-2007 à 16:05:48    

Voilà, j'ai un petit problème - qui est d'ailleurs exposé dans un sujet là : http://forum.hardware.fr/hfr/Progr [...] 6359_1.htm  
Cadre : une appli VB, une base access à laquelle cette appli accède.
Il faut que je fasse un update d'une valeur, or cette valeur est une clé dans 3 tables, et du coup ça ne marche que si je supprime l'intégrité référentielle entre ces tables. Ce qui est une mauvaise chose.
 
Je voudrais donc savoir s'il est possible de coder dans VB un ordre pour désactiver l'intégrité référentielle sur la relation R, puis faire ma manip, puis remettre l'intégrité sur R.  
Est-ce que je rêve trop ou c'est faisable ?  
Car c'est dur de trouver de la doc la dessus !
 
Merci.


Message édité par belsuncette le 26-07-2007 à 14:47:30
Reply

Marsh Posté le 19-07-2007 à 16:05:48   

Reply

Marsh Posté le 19-07-2007 à 16:14:33    

Désactiver une contrainte je sais pas si c est possible en access encore moins :) Par contre tu peux la virer et la recreer apres dans ton programme.
 
Enfin derniere chose si tu dois faire ce genre de manip :
- soit ta contrainte est inutile alors il faut la virer
- soit ta manip est dangereuse
 
Si des contraintes sont placées c est justement qu il y a une raison ;) Dans ton cas tu vas faire un update d une valeur qui n est pas référencé dans une autre table, un moment ou à un autre ca va etre le bordel dans tes données...

Reply

Marsh Posté le 19-07-2007 à 16:16:56    

Hop voila un lien pour desactiver une contrainte en SQL --> http://www.databasejournal.com/sql [...] hp/1490991
 
Pas sur que ca marche en Access

Reply

Marsh Posté le 20-07-2007 à 08:48:26    

Merci je vais me plonger dans ça. Y'a pas mal de commandes SQL qui marchent depuis VB pour une base access. Il faut juste identifier laquelle gère l'intégrité référentielle.
Sinon, pas de danger normalement avec cette manip, le truc c'est que je veux changer un numéro de client partout mais qu'il faudrait pouvoir faire ça exactement en même temps dans toutes les tables où ce numéro sert de clé....
Il faut donc virer la contrainte à ce moment là, sinon quand on veut faire l'update dans une table ça refuse à cause des autres tables.  
Je ne nie pas que la base est pas top au niveau normalisation mais elle a déjà quelques années et c'est impossible de tout casser maintenant vu la quantité de données (mais pourtant ça me démange :D).  
Je ne sais pas si la contrainte est utile ailleurs, mais je ne veux pas prendre le risque de la supprimer...

Reply

Marsh Posté le 20-07-2007 à 09:10:09    

À ma connaissnace, on ne peut pas simplement désactiver les relations d'intégrité dans Access.
Il faut supprimer puis recréer la relation (objet Relations et méthode .CreateRelation)
 
Tu peux aussi définir ta relation pour permettre la mise à jour en cascade des clés.
Ça t'éviterais d'avoir à recommencer cette manipulation.

Reply

Marsh Posté le 20-07-2007 à 09:20:36    

La mise à jour en cascade est déjà activée. Cela fonctionne en partie quand on met à jour NumClient, clé de TableClient : les tables où NumClient est une clé étrangère ont bien la valeur mise à jour. Le problème se pose dans les tables (il y en a 2 dans ce cas) où NumClient est aussi une clé primaire : dans ce cas la mise à jour en cascade ne fonctionne pas - et du coup tout l'update est refusé.
 
La piste d'Oreste m'a conduite à trouver l'option dbInconsistent dans la méthode execute de VB (database.execute(requete)). Je suis en train de voir si ça peut marcher...


Message édité par belsuncette le 20-07-2007 à 09:20:49
Reply

Marsh Posté le 20-07-2007 à 09:50:10    

belsuncette a écrit :

c'est impossible de tout casser maintenant vu la quantité de données


 
impossible n'est pas francais, qté de données ou pas :p

Reply

Marsh Posté le 20-07-2007 à 09:54:09    

Oui mais mon contrat était trop court pour me lancer dans ça même si je l'ai proposé parce que je m'arrachais les cheveux de voir ça :D

Reply

Marsh Posté le 20-07-2007 à 09:59:22    

Rhooo, ça marche toujours pas :'(

Reply

Marsh Posté le 20-07-2007 à 10:20:14    

dbInconsistent est un paramètre par défaut je crois et ne passe pas outre les relations d'intégrité référentielle.

 

Message cité 1 fois
Message édité par tegu le 20-07-2007 à 10:20:24
Reply

Marsh Posté le 20-07-2007 à 10:20:14   

Reply

Marsh Posté le 20-07-2007 à 10:23:02    

Hmm belsuncette comment ca se fait que numclient soit clé primaire sur 2 tables ? je trouve ca bizarre...

Reply

Marsh Posté le 20-07-2007 à 10:26:13    

En fait c'est la clé primaire de Client. Et puis il y a une relation 1-1 avec 2 autres tables dans lequel il sert de clé aussi... Je suis d'accord que c'est pas top mais ça a été conçu comme ça, et je pense que ça devait être par nécessité car les 2 autres tables ont énormément de champs, ça devait être pour ne pas surcharger.  
Enfin bon, je suis pas aidée par cette BD, c'est sûr !!!!  :pfff:


Message édité par belsuncette le 20-07-2007 à 10:28:17
Reply

Marsh Posté le 20-07-2007 à 10:28:02    

tegu a écrit :

dbInconsistent est un paramètre par défaut je crois et ne passe pas outre les relations d'intégrité référentielle.
 


 
 
Tu sais pas ce qui le ferait ? Parce que en effet ça ne fait pas grand chose.  
Les trucs de type "NOCHECK" me tentaient (cf le lien d'Oreste) mais le problème c'est qu'il faut nommer les contraintes sur lesquelles on CHECK ou pas, et moi c'est pas une contrainte que j'ai créée mais une contrainte d'Access.
 
  :cry:

Reply

Marsh Posté le 20-07-2007 à 10:36:34    

Je suis désolé de me citer mais « À ma connaissnace, on ne peut pas simplement désactiver les relations d'intégrité dans Access.  »
 
J'ai quelques années d'Access derrière moi, certes pas sur les versions les plus récentes mais j'ai un doute sur la faisabilité de ton truc sans suppression de la relation.
 
Je ne demande qu'à être contredit, ceci-dit, pour t'éviter du boulot inutile :)

Reply

Marsh Posté le 20-07-2007 à 10:47:26    

Ouin....j'aimerais aussi que tu aies tort, mais je te fais confiance, malheureusement !
 
Tant pis ils devront continuer à aller désactiver à la main l'intégrité (ça on peut le faire par contre, en cliquant sur la relation), puis faire leur modif, et la remettre....C'est déjà un progrès vu que jusqu'à maintenant ils allaient carrément supprimer la relation, mais bon, l'idée c'était que je trouve comment faire ça plus simplement.
 
Merci quand même :)

Reply

Marsh Posté le 20-07-2007 à 13:32:50    

Ben tu peux coder la suppression puis la recréation de la relation (objet Relations et méthode .CreateRelation).
Pas obligé de passer par l"interface et de le faire manuellement.

Reply

Marsh Posté le 20-07-2007 à 13:59:13    

Ca me parait pas mal, ça. Est-ce que tu sais (ou connais un bon tutorial qui le dit) comment on peut désigner la relation visée ?

Reply

Marsh Posté le 20-07-2007 à 14:35:31    

L'aide en ligne (F1) est suffisante.

Reply

Marsh Posté le 20-07-2007 à 14:49:21    

Oui l'aide de VB est vraiment bien, mais mes relations dans la base Access n'ont pas de nom, du coup je ne vois pas comment identifier la propriété Name de la relation que je veux supprimer ? ou au moins leur numéro. La méthode Delete a besoin d'un des 2.
 
Dans l'aide d'access, que je trouve beaucoup moins bien que celle de VB, je trouve ça, pour l'instant :
 
POUR CHANGER LE NOM D'UNE RELATION :
"Dans la fenêtre Base de données, cliquez sur Schémas de base de données  sous Objets. Cliquez ensuite sur le schéma de base de données que vous souhaitez ouvrir, puis sur Modifier dans la barre d'outils de la fenêtre Base de données.  
Dans votre schéma de base de données, sélectionnez la ligne représentant la relation que vous voulez renommer.  
Cliquez avec le bouton droit sur la ligne de relation et sélectionnez Propriétés.  
Choisissez l'onglet Relations.  
Dans la zone Nom de la relation, entrez un nouveau nom."
 
mais je n'ai pas ça, moi   :na:  
Edit : c'est normal, c'est pour des projets access de type "ADP", je ne sais pas ce que c'est mais le mien est de type "MDB".
 
Je continue à chercher  :bounce:


Message édité par belsuncette le 20-07-2007 à 15:01:06
Reply

Marsh Posté le 20-07-2007 à 15:19:09    

Les projets ADP sont des projets Access partagés.
Le nom d'une relation est la concaténation des noms des tables impliquées, de mémoire.
Sinon tu dois pouvoir parcourir la collection des relations et tester .Table et .ForeignTable


Message édité par tegu le 20-07-2007 à 15:20:30
Reply

Marsh Posté le 20-07-2007 à 15:31:13    

Je venais de tester la concaténation, mais ça me dit "élément non trouvé dans cette collection". Je poursuis, je poursuis....Merci beaucoup de ton aide en tout cas, je vais bien finir par y arriver finalement :)

Reply

Marsh Posté le 20-07-2007 à 15:52:08    

Bon, alors en fait, après une petite boucle qui teste .Table et .ForeignTable, j'ai pu trouver le nom des relations que je veux, et c'est effectivement une concaténation des noms des tables, mais précédée du chemin d'accès de la base, ce qui donne qqch comme :
" [C:\DossierBelsuncette\BaseClient.mdb].Table2Table1"
 
La suppression de la relation marche bien. Du coup je suis confiante pour ma mise à jour !!!


Message édité par belsuncette le 20-07-2007 à 15:52:27
Reply

Marsh Posté le 23-07-2007 à 12:06:07    

Re moi, je garde le même sujet : j'ai du mal avec CreateRelation.
Pour l'instant je fais  
   Set Regeneration_HistoPrel = db.CreateRelation(, "HistoPrel", "Client", dbRelationUpdateCascade)
   db.Relations.Append Regeneration_HistoPrel
 
Mais ça me le refuse, et je n'arrive pas à savoir pourquoi exactement. Le message d'erreur est incomplet, il dit qu'il n'arrive pas à trouver qqch mais ne le nomme pas, et dit que c'est peut-être un mauvais alias. Je pense que ça vient du nom des tables mais je ne sais pas quoi mettre : j'ai essayé avec leur nom, puis leur nom précédé du chemin complet, mais ça ne change rien.
L'erreur se produit au moment du Append : si j'ai bien compris, il est nécessaire pour que les relations soient effectivement créées...
Je dois mal m'y prendre :/

Reply

Marsh Posté le 23-07-2007 à 14:16:04    

Effectivement tu t'y prends mal :)
Une relation n'est pas seulement définie par le nom des tables en relation, mais surtout par la correspondance des champs de clé.
Quand tu crées un objet relation, il ne fait pas l'appariement automatiquement entre les champs clé, même si les noms sont identiques.
Tu dois passer par la création d'objets champs et les ajouter à la collection des champs de ta relation.
 

Dim fld As Field, r As Relation, db As Database
...
Set r = db.CreateRelation(,table1, table2, dbRelationUpdateCascade)
Set fld = r.CreateField("NomDuchamp1Table1" )
fld.ForeignName = "NomDuChamp1Table2"
r.Fields.Append fld
 
Set fld = r.CreateField("NomDuchamp2Table1" )
fld.ForeignName = "NomDuChamp2Table2"
r.Fields.Append fld
 
db.Relations.Append r
db.Relations.Refresh

Reply

Marsh Posté le 23-07-2007 à 15:50:59    

J'ai toujours une erreur au moment du db.Relations.Append : la même, il dit qu'il ne trouve pas ce quelquechose qu'il nomme :   ".
Je ne sais vraiment pas d'où ça vient. J'ai essayé de spécifier les chemins : pour les tables et pour les champs, mais je ne suis pas sûre de bien le faire non plus.
Par exemple, pour les tables, je me base sur ce qui m'était renvoyé quand je recherchais les noms des relations, et ça donne donc un truc de ce style :  
"[C:\Copie_Belsuncette\Base2307.mdb].HistoDup"
Et j'essaie aussi sans chemin ; ça dit pareil.  
Est-ce qu'il faut aussi créer des TableDef ?  
 
PS : effectivement c'était bête de ne pas spécifier les champs de la relation ;)

Reply

Marsh Posté le 23-07-2007 à 16:12:32    

Quand tu dis que tu essaies sans chemin, tu n'oublierais pas d'enlever le point aussi ?
Ton message d'erreur semble dire que le problème est lié à la mauvaise utilisation de ce caractère.

Reply

Marsh Posté le 23-07-2007 à 16:17:23    

Sans chemin, je ne mets pas le point, et avec chemin, je le mets puisque c'était comme ça dans le nom de la relation....
Je suis près du but pourtant (de mon but initial ;)) c'est rageant :D

Reply

Marsh Posté le 23-07-2007 à 16:40:40    

Est-ce que tes tables contiennent des enregistrements quand tu établis la relation ?
Si oui, il se peut que leur contenu soit incompatible avec cette relation.
Du genre un champ clé mal renseigné, qui n'a pas déquivalent dans la table liée.


Message édité par tegu le 23-07-2007 à 16:42:50
Reply

Marsh Posté le 23-07-2007 à 16:43:55    

Ben vu que je supprime la relation juste avant, toutes les données devraient satisfaire la nouvelle relation identique à l'ancienne...
A savoir, le champ impliqué dans la relation que je crée est la clé pour chacune des 2 tables.

Reply

Marsh Posté le 23-07-2007 à 16:46:03    

Oui c'est vrai.
Bon, du coup, je ne vois pas trop ce qui pose problème.
J'aimerais que tu nous montres ton code actuel pour faire un test chez nous si possible.
Au moins une version simplifiée qui ne fonctionne pas chez toi.

Reply

Marsh Posté le 23-07-2007 à 17:01:57    

Ca me parait un peu compliqué de tout vous envoyer, alors je ne sais pas si ça serait suffisant :
il faut
- une table Client avec la clé NumClient, le reste on s'en fout
- une table HistoPrel avec la clé NumClient aussi
 
Mon code pour créer la relation :
 

Code :
  1. Dim Regeneration_HistoPrel As Relation 
  2.    Dim Fld As Field
  3.  
  4.    Set Regeneration_HistoPrel = db.CreateRelation(, "HistoPrel", "Client", dbRelationUpdateCascade + dbRelationUnique)
  5.    Set Fld = Regeneration_HistoPrel.CreateField("NumClient" )
  6.    Fld.ForeignName = "NumClient"
  7.    Regeneration_HistoPrel.Fields.Append Fld
  8.  
  9.    db.Relations.Append Regeneration_HistoPrel
  10.    db.Relations.Refresh


Il faut juste lier la base à l'appli VB, dis moi si tu as besoin d'autre chose. Ici c'est fait comme ça, avec le nom de la base dans 'bd' :
 
    Set wrkJet = CreateWorkspace("", "admin", "", dbUseJet)
    Set db = wrkJet.OpenDatabase(bd, _
      False)
 
Sinon j'ai testé et contrairement aux relations, quand il trouve les noms des tables il n'y a pas tout le préfixe, seulement le nom de la table. Alors du coup moi non plus je ne vois pas d'où ça vient !
Je n'ai pas réussi à faire la même chose pour les attributs et voir comment ils sont nommés ici - j'avais essayé un truc du style "[HistoPrel].NumClient" mais toujours pas ça....
 
Merci beaucoup pour ton aide, en tout cas !


Message édité par belsuncette le 23-07-2007 à 17:03:00
Reply

Marsh Posté le 23-07-2007 à 17:19:21    

Résultat des courses, si j'utilise

Set Regeneration_HistoPrel = db.CreateRelation(, "HistoPrel", "Client", dbRelationUpdateCascade + dbRelationUnique)

j'obtiens la même erreur que toi.
Si je rajoute un nom à ma relation ça ne déclenche pas d'erreur.

Set Regeneration_HistoPrel = db.CreateRelation("HistoPrelClient", "HistoPrel", "Client", dbRelationUpdateCascade + dbRelationUnique)

Reply

Marsh Posté le 24-07-2007 à 08:44:58    

Génial, merci pour ce tuyau, j'avais mis un nom à un moment mais certainement avec plein d'autres trucs faux.
 
Ce matin, gros espoir, et la : DAMNED => "Opération non gérée sur des tables attachées"...... :'(
Je vais y arriver ;) J'imagine qu'il faut aller faire ça directement dans la BD et non la BD qui lui est liée. Bizarre pourtant, le Delete marche très bien, lui.....
Bon, vais tenter d'accéder à la BD principale.


Message édité par belsuncette le 24-07-2007 à 08:48:06
Reply

Marsh Posté le 24-07-2007 à 09:02:50    

C'est bizarre, quand je recrée, il me dit que l'objet "HistoPrelClient" existe déjà...
 
Et puis ça m'envoie bouler pour recréer la relation sous un autre nom, mais cette fois c'est parce que la BD est accédée sur d'autres postes en ce moment. Je verrai ce que ça donne quand personne n'y touche, c'est gérable. Mais je me demande si nommer la relation différemment à chaque fois a des conséquences ? Genre, il stocke toutes les relations quand même ??? Parce qu'après le Delete, elle disparaît bien du schéma avec les relations.
 
Il faut que je voie si après un renommage, la relation est bien retrouvée au passage suivant, pour savoir si ça sert à qqch de faire ça. Mais pour ça il faut que je fasse déconnecter tout le monde  :sarcastic:


Message édité par belsuncette le 24-07-2007 à 09:08:26
Reply

Marsh Posté le 24-07-2007 à 15:10:29    

Une dernière question, tegu :
ça marche finalement (victoire !!!!), par contre il reste un petit défaut.
Je supprime les relations, je fais mes modifs, je recrée les relations.  
Si je réessaie de faire un autre changement de numéro tout de suite, il ne trouve pas la relation nouvellement recréée. Par contre, si je sors de mon appli et que j'y rerentre, il la trouve.
Saurais-tu pourquoi, car je fais des refresh et append ?  
Sinon, tant pis, c'est déjà pas mal ;) Merci ENORMEMENT de ce dépannage.

Reply

Marsh Posté le 24-07-2007 à 15:19:07    

Si tu fais bien un db.Relations.Refresh après ton .Append, je ne vois pas pourquoi ça ne marche pas.
Essaie de faire aussi un .Refresh sur la collection des .QueryDefs de ta base. On ne sait jamais.

Reply

Marsh Posté le 24-07-2007 à 15:49:53    

Sans le vouloir, tu m'as répondu : en fait, je faisais le Refresh dans la base distante puisqu'il faut créer les relations dedans, comme je l'ai vu plus haut.
En faisant le relations.refresh sur cette base, ça n'était pas suffisant : il faut aussi le faire sur la base locale car c'est dans cette base que les relations sont supprimées. En fermant et rouvrant l'appli, il trouvait bien toutes les relations, mais sinon la base locale restait ouverte et n'était pas mise à jour.
Et voilà, maintenant ça marche et c'est super !!!!!!!!!!!
Je ne sais pas comment te remercier !!

Reply

Marsh Posté le 24-07-2007 à 16:54:05    

« Je ne sais pas comment te remercier !! » Oula, tu prends des risques !
Blague à part, ça fait plaisir de pousser les wagonnets avec les débutants qui s'en donnent la peine.
On est tous au fond de la même mine. Je creuse juste depuis plus longtemps :)

Reply

Marsh Posté le 24-07-2007 à 16:57:17    

+1  :pt1cable:

Reply

Marsh Posté le 25-07-2007 à 08:37:43    

Et bien merci encore, de prendre du temps pour des gens comme moi :)

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed