Voir le flux RSS

Le Blog de DSR57 - Programmation WinDev

[Actualité] WinDev : HsupprimeTout qui supprime tout

Noter ce billet
par , 05/08/2015 à 14h08 (1161 Affichages)
Surcharge de la fonction HSupprimeTout avec prise en charge des contraintes d'intégrité référentielle

Contexte Technique



Nom : contexteTechnique.jpg
Affichages : 2111
Taille : 27,5 Ko

Dans un premier billet WinDev : HsupprimeTout et les contraintes d'intégrité référentielle en cascade, nous constations avec la confirmation du support technique la non prise en charge les contraintes d'intégrité référentielle définies dans l'analyse par la fonction HsupprimteTout .

Dans le but de palier à ce manque, ce bogue, cet oublie (chacun le qualifiera comme il le souhaite), j'ai développé une fonction qui prend en charge les contraintes d'intégrité.

Version de WinDev : 20 et antérieures
Programmation : surcharge, exceptions.

Jeu d'essai



Nom : practiceTest.jpg
Affichages : 1443
Taille : 8,9 Ko

Avant de mettre le code de la fonction développée, je met à disposition le jeu d'essai qui m'a permis de faire les tests.

Commande


Nom du fichier : commande.FIC

Clé Nom Libellé Type Taille
X ID Identifiant de la commande Id. automatique 4
Date Date de la commande Date 8
Client Nom du client Texte 50

DetailCommande

Nom du fichier : DetailCommande.FIC

Clé Nom Libellé Type Taille
X ID Identifiant du détail de la commande Id. automatique 4
IDCommande Identifiant de la commande Numérique 4
IdArticle Identifiant de l'article Numérique 4

Une relation entre les deux table est créée, cell-ci varie selon de vos contextes technique et focntionnel

Script d'initialisation

Ci-dessous le script d'initialisation des tables

Code WinDev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
HCréationSiInexistant(Commande)
HCréationSiInexistant(CommandeDetail)
 
WL.HSupprimeTout(Commande)
WL.HSupprimeTout(CommandeDetail)
 
POUR li_i=1 _A_  10 
	Commande.Date=DateDuJour()
	Commande.Numero=NumériqueVersChaîne(li_i,"010d")
	Commande.Client="ClientTest_"+li_i
 
	HAjoute(Commande)
 
	POUR li_j=li_i _A_ li_i+3 
		CommandeDetail.IDCommande=Commande.ID
		CommandeDetail.IdArticle=li_j
		HAjoute(CommandeDetail)
	FIN
 
FIN

Nom : Sans titre.png
Affichages : 1484
Taille : 11,7 Ko
Contenu de la table commande initialisée avec le script

Nom : Sans titre.png
Affichages : 1447
Taille : 16,1 Ko
Contenu de la table détail commande initialisée avec le script

La nouvelle fonction



Nom : photo_programmation_web.png
Affichages : 1523
Taille : 172,3 Ko

Le nom de la fonctions a été créé en conservant la même syntaxe que celles proposées par PC-Soft
Nom : HSupprimeTout
Cette nouvelle fonction surcharge l'existante, WinDev affichera des informations a chaque appel de celle-ci.

Exemple d'information affichée :
Code Windev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
Info : La procédure 'HSupprimeTout' surcharge la fonction du WLangage de même nom.
Fen_TestPROCEDURE.HSupprimeTout, Procédure locale, ligne 13, colonne 11

La fonction gère les contraintes d'intégrité :
  • interdire la supression qui a au moins un enregistrement
  • supprimer l'enregistrement et tous ces détails
  • supprimer l'enregistrement et affecter une valeur par défaut aux détails

et la gestion des cardinalités minimums

Code WinDev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Résumé : Supprime tout le contenu d'un fichier en prenant en compte les contraintes d'intégrité
// Syntaxe :
//HsupprimeTout(ps_nomFichier est une chaine)
//
// Paramètres :
//	ps_nomFichier : Nom du fichier de données
// Valeur de retour :
// 	booléen : vrai si le contenu du fichier a été supprimer.
//
// Exemple :
// HsupprimeTout(Commande..Nom)
//
 
PROCEDURE HsupprimeTout(ps_nomFichier est une chaîne)
 
//----->Declaration des variables
ls_LstLiaison,ls_nomLiaison,ls_FichierClePrimaire, ls_clePrimaire, ls_fichierCleEtrangere, ls_CleEtrangere, ls_regleSupression, ls_cardinaliteFichierPrimaire, ls_cardinaliteFichierSecondaire est une chaîne
ls_LstValeurLiees,ls_nomFichierParametre, ls_requete, ls_nomReq  est une chaîne
ls_MessageException1, ls_MessageException2, ls_MessageException3, ls_MessageException4 est une chaîne
lt_BufferRequete est un tableau de chaîne
 
//----->Initialisation des variables Message Exception
ls_MessageException1=[
La  source de données <%1> n'est pas initialisée.
     - S'il s'agit d'un fichier de données, le fichier n'a pas été trouvé dans l'analyse ou n'a pas été décrit avec les fonctions HDéclare / HDéclareExterne.
     - S'il s'agit d'une requête ou d'une vue, l'exécution a peut-être échoué. 
Pour récupérer l'erreur correspondante, testez le résultat des fonctions HExécuteRequête / HExécuteRequêteSQL / HCréeVue.
]
ls_MessageException2="Le champ '%1' n'est pas de type Fichier de données"
ls_MessageException3=[
	Erreur d'intégrité.
	L'application de la fonction aurait entraîné le non-respect de la contrainte d'intégrité référentielle 'restrict' entre les rubriques <%1.%2> (clé primaire) ET <%3.%4> (clé étrangère).
]
ls_MessageException4=[
Erreur d'intégrité.
Les cardinalités côté clé primaire (%1) entre les rubriques <%2.%3> et <%4.%5> ne sont pas respectées.
]
 
//----->Initialisation des variables
ls_nomFichierParametre=ps_nomFichier
 
//----->Test si la variable passé en paramètre existe en tantque fichier de données
QUAND EXCEPTION DANS
	HLitPremier(ls_nomFichierParametre)	
FAIRE
	ExceptionDéclenche(1,ChaîneConstruit(ls_MessageException1,ls_nomFichierParametre))
FIN
 
//----->Test du type du pamètre
SI PAS ({ls_nomFichierParametre}..Type _DANS_ (hFichierAS400, hFichierAutre, hFichierClientServeur, hFichierHF5, hFichierMySQL, hFichierNormal, hFichierOLEDB, hFichierOracle, hFichierOracleLite, hFichierPostgreSQL, hFichierProgress)) ALORS
	ExceptionDéclenche(2,ChaîneConstruit(ls_MessageException2,ls_nomFichierParametre))
FIN
 
//----->Rcp des liaisons liés au fichier passé en paramètre
ls_LstLiaison=HListeLiaison(ls_nomFichierParametre,hLstDétail) 
 
//----->Boucle sur toutes les liaisons
POUR TOUTE CHAÎNE ls_liaison DE ls_LstLiaison SEPAREE PAR RC
 
	//----->Récupération des caractéristiques de la liaison
	ls_nomLiaison=ExtraitChaîne(ls_liaison,1,TAB,DepuisDébut)
	ls_FichierClePrimaire=ExtraitChaîne(ls_liaison,2,TAB,DepuisDébut)
	ls_clePrimaire=ExtraitChaîne(ls_liaison,3,TAB,DepuisDébut)
	ls_cardinaliteFichierPrimaire=ExtraitChaîne(ls_liaison,4,TAB,DepuisDébut)
	ls_fichierCleEtrangere=ExtraitChaîne(ls_liaison,5,TAB,DepuisDébut)
	ls_CleEtrangere=ExtraitChaîne(ls_liaison,6,TAB,DepuisDébut)
	ls_cardinaliteFichierSecondaire=ExtraitChaîne(ls_liaison,7,TAB,DepuisDébut)
	ls_regleSupression=ExtraitChaîne(ls_liaison,9,TAB,DepuisDébut)
 
	SI ls_FichierClePrimaire = ls_nomFichierParametre ALORS
 
		SI Val(ExtraitChaîne(ls_cardinaliteFichierSecondaire,1,",",DepuisDébut)) > 0  ALORS
			ExceptionDéclenche(3,ChaîneConstruit(ls_MessageException4,ls_cardinaliteFichierSecondaire,ls_fichierCleEtrangere,ls_CleEtrangere,ls_FichierClePrimaire,ls_clePrimaire))
		FIN
 
		//----->Initialisation des variables
		ls_LstValeurLiees=""
 
		//----->Req : recherche des valeurs à supprimer dans le fichier source
		ls_requete="SELECT DISTINCT  "+ls_clePrimaire+" FROM "+ls_FichierClePrimaire			
		ls_nomReq="ReqSelectValeurASupprimer"
 
		//----->Req : Exécution et parcours de la requete
		SI PAS HExécuteRequêteSQL(ls_nomReq,ls_requete) ALORS
			HFerme(ls_nomReq)
			RENVOYER Faux
		SINON
			HLitPremier(ls_nomReq) 
			TANTQUE PAS HEnDehors(ls_nomReq) 
				ls_LstValeurLiees+=HRécupèreRubrique(ls_nomReq,1)+"','"
				HLitSuivant(ls_nomReq)
			FIN
			HLibèreRequête(ls_nomReq)
			SI ls_LstValeurLiees <> "" ALORS
				ls_LstValeurLiees="'"+Tronque(ls_LstValeurLiees,3,nombreDeCaractèresASupprimer)+"'"
			FIN
		FIN
 
		//----->Test si des valeurs sont à suppimer
		SI ls_LstValeurLiees<>"" ALORS
 
			//----->Test selon la regle de suppression
			SELON ls_regleSupression
 
				CAS hIntégritéInterdite
					//---->Req : Test si des enregistrements sont reliés au fichier source par le svaleurs à supprimer
					ls_requete="SELECT COUNT(*) FROM "+ls_fichierCleEtrangere+" WHERE "+ls_CleEtrangere+" IN ("+ls_LstValeurLiees+")"
					ls_nomReq="reqUpdateDetail"
 
					//----->Req : Exécution et parcours
					SI PAS HExécuteRequêteSQL(ls_nomReq,ls_requete) ALORS
						HFerme(ls_nomReq)
						RENVOYER Faux
					SINON
						HLitPremier(ls_nomReq) 
						//----->Test si des enregistrements sont reliés : on ne fait rien
						SI HRécupèreRubrique(ls_nomReq,1) <> 0 ALORS
							HLibèreRequête(ls_nomReq)
							ExceptionDéclenche(3,ChaîneConstruit(ls_MessageException3,ls_FichierClePrimaire,ls_clePrimaire,ls_fichierCleEtrangere,ls_CleEtrangere))
						FIN
						HLibèreRequête(ls_nomReq)
					FIN
 
				CAS hIntégritéCascade
					//----->Req : Ajout dans le buffer la requête de suppression des enregistrements reliés au fichier source par le svaleurs à supprimer
					TableauAjoute(lt_BufferRequete,"DELETE FROM  "+ls_fichierCleEtrangere+" WHERE "+ls_CleEtrangere+" IN ("+ls_LstValeurLiees+")")
 
				CAS hIntégritéValeurDéfaut
					//----->Req : Ajout dans le buffer la requête de maj des enregistrements par la valeur par défaut reliés au fichier source par le svaleurs à supprimer
					TableauAjoute(lt_BufferRequete,"UPDATE  "+ls_fichierCleEtrangere+" SET "+ls_CleEtrangere+"='"+{ls_fichierCleEtrangere+"."+ls_CleEtrangere,indRubrique}..ValeurParDéfaut+"' WHERE "+ls_CleEtrangere+" IN ("+ls_LstValeurLiees+")")
 
				AUTRE CAS
 
			FIN
		FIN
	FIN
FIN
 
//----->Exécution des requêtes pour mettre en place les contraintes d'intégrité
POUR li_i=1 _A_ TableauInfo(lt_BufferRequete,tiNombreTotal)
	SI HExécuteRequêteSQL("Req"+li_i,lt_BufferRequete[li_i]) = Faux ALORS
		ExceptionDéclenche(3,HErreurInfo(hErrComplet))
	FIN
FIN
 
SI WL.HSupprimeTout(ps_nomFichier) ALORS
	RENVOYER Vrai
SINON
	RENVOYER Faux	
FIN

j'ai effectué différents tests en variant les contraintes d'intégrité avec le code suivant :

Suppression complète du contenu du fichier commande
Code Windev : Sélectionner tout - Visualiser dans une fenêtre à part
HSupprimeTout(Commande..nom)

Suppression complète du contenu du fichier DetailCommande
Code Windev : Sélectionner tout - Visualiser dans une fenêtre à part
HSupprimeTout(DetailCommande..nom)


Les exceptions

Comme vous avez pu le constater en lisant le code source des fonctions, celles-ci déclenchent des exceptions en cas de problème. Trois types d'exceptions sont gérées :


Code Message
1 La source de données <%1> n'est pas initialisée.
- S'il s'agit d'un fichier de données, le fichier n'a pas été trouvé dans l'analyse ou n'a pas été décrit avec les fonctions HDéclare / HDéclareExterne.
- S'il s'agit d'une requête ou d'une vue, l'exécution a peut-être échoué.
Pour récupérer l'erreur correspondante, testez le résultat des fonctions HExécuteRequête / HExécuteRequêteSQL / HCréeVue.
2 Le champ '%1' n'est pas de type fichier de données
3 Erreur d'intégrité.
Les cardinalités côté clé primaire (%1) entre les rubriques <%2.%3> et <%4.%5> ne sont pas respectées

ou

Erreur d'intégrité.
L'application de la fonction aurait entraîné le non-respect de la contrainte d'intégrité référentielle 'restrict' entre les rubriques <%1.%2> (clé primaire) ET <%3.%4> (clé étrangère)

Exemple de code avec la gestion des exceptions :


Code WinDev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
QUAND EXCEPTION DANS 
	HSupprimeTout(Commande..nom)
FAIRE
	//Gestion des exceptions
FIN

Conclusion



Ce billet propose une surcharge de la fonction HSupprimeTout pour prendre en compte les contraintes d'intégrité, celle-ci ne gère qu'un seul niveau. Si le fichier de destination est lié lui aussi à des containtes, celles-ci ne sont pas prises en compte, cela pourrait faire office d'une verison 2 ...

Si vous avez des remarques, des suggestions, des remotées de BUG, ... n'hésitez pas

Bon dev

Envoyer le billet « WinDev : HsupprimeTout qui supprime tout » dans le blog Viadeo Envoyer le billet « WinDev : HsupprimeTout qui supprime tout » dans le blog Twitter Envoyer le billet « WinDev : HsupprimeTout qui supprime tout » dans le blog Google Envoyer le billet « WinDev : HsupprimeTout qui supprime tout » dans le blog Facebook Envoyer le billet « WinDev : HsupprimeTout qui supprime tout » dans le blog Digg Envoyer le billet « WinDev : HsupprimeTout qui supprime tout » dans le blog Delicious Envoyer le billet « WinDev : HsupprimeTout qui supprime tout » dans le blog MySpace Envoyer le billet « WinDev : HsupprimeTout qui supprime tout » dans le blog Yahoo

Mis à jour 29/08/2015 à 01h06 par dsr57

Catégories
WinDev , Fonctions

Commentaires