IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

WinDev Discussion :

Utilisation des User-Defined Types de SQL Server avec Windev [WD18]


Sujet :

WinDev

  1. #1
    Membre expérimenté
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2012
    Messages : 162
    Par défaut Utilisation des User-Defined Types de SQL Server avec Windev
    Bonjour et bon début de semaine à tous,

    Je me tourne vers vous car après toutes mes recherches, je n'ai pas trouvé de solution à mon problème.

    Je suis en train de d'étayer mon Proof of Concept avant de me lancer dans un développement WinDev 18-SQL Server 14 sans l'utilisation des accès natifs.
    Et je souhaiterais effectuer toutes les opérations de mise à jour des données (INSERT/UPDATE/DELETE) par le biais de procédures stockées avec en entrée les paramètres de type des User-Defined types.
    Cependant, il se pose le problème du passage de ces paramètres coté WinDev. J'ai vu plusieurs cas de passage de données simples (entier, chaine, etc) mais pour les listes ou les tableaux il n'y a pas d'indications.

    Y'aurait-il des développeurs qui ont été confrontés à la même problématique? Si oui, comment avez vous solutionné le problème?

    Cordialement

  2. #2
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2003
    Messages
    1 045
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2003
    Messages : 1 045
    Par défaut
    Bonjour,

    Je n'ai jamais tenté l'expérience, mais peux-tu nous dire si tu utilises de l'oledb ou l'ODBC ?

    Cordialement,

    Philippe SAINT-BERTIN

  3. #3
    Membre expérimenté
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2012
    Messages : 162
    Par défaut
    Citation Envoyé par philouZ Voir le message
    Bonjour,

    Je n'ai jamais tenté l'expérience, mais peux-tu nous dire si tu utilises de l'oledb ou l'ODBC ?

    Cordialement,

    Philippe SAINT-BERTIN
    Bonjour et merci de l'intérêt porté à la question.

    J'utilise l'OLEDB pour l'opération

    Cordialement

  4. #4
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2003
    Messages
    1 045
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2003
    Messages : 1 045
    Par défaut
    perso avec l'accès par oledb j'ai rencontré pas mal de problèmes, de requêtes un peu complexes qui ne passait pas ou tout simplement des procédures stockées que je n'ai jamais pu appeler. J'ai du coup utilisé l'accès par ODBC et à partir de là, j'ai pu réaliser tout ce que je souhaitais, jusqu'à pouvoir exécuter du T-SQL.

    Peut-être peux tu axer tes recherches vers ce type de connexion.

    Cordialement,

    Philippe SAINT-BERTIN

  5. #5
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    732
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 732
    Par défaut
    Attention, en OLE DB beaucoup de limitations voire bugs sont dus au type de curseur par défaut.
    En curseur client et avec hRequêteSansCorrection par exemple, beaucoup de choses fonctionnent mieux.

  6. #6
    Membre expérimenté
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2012
    Messages : 162
    Par défaut
    Merci pour vos remarques. Ça pourrait toujours être salutaire en temps utile.
    Je continue de peaufiner mon architecture.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    176
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 176
    Par défaut
    Je travaille avec des procédures stockées en MS-SQL. Ça m'a bien prit la tête au début...

    Pour finir, je travaille uniquement avec hRequêteSansCorrection

    Au début, je travaillais comme ça :

    Code : 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
     
     
    //Description de la connexion
    gcnxMaConnexion..Utilisateur = gsDbLogin
    gcnxMaConnexion..MotDePasse = gsDbPassword
    gcnxMaConnexion..Serveur = gsNomServer //+ "," + gsPortServer
    gcnxMaConnexion..BaseDeDonnées = gsDbName
    gcnxMaConnexion..Provider = hAccèsNatifSQLServer
    gcnxMaConnexion..Accès = hOLectureEcriture
     
    //On injecte les données d'adresses
    sdAjouterAdresseClient.PAdresseClient = TABLE_TableAdresse.COL_Adresse[i]
    sdAjouterAdresseClient.PIdTypeAdresse = TABLE_TableAdresse.IDTypeAdresse[i]
    sdAjouterAdresseClient.PIdClient = gxIDClientCree
    sdAjouterAdresseClient.PSaisiPar = gsLoginUtilisateur
    sdAjouterAdresseClient.PIDVille = gxIDVille
    sdAjouterAdresseClient.PIDPrefix_adresse  = TABLE_TableAdresse.COL_IdPrefixAdresse[i]
    sdAjouterAdresseClient.PIDTournee = TABLE_TableAdresse.COL_IDTournee[i]
    sdAjouterAdresseClient.PCommentaireLiv = TABLE_TableAdresse.COL_CommentaireLiv[i]
    sdAjouterAdresseClient.PCommentaireMat = TABLE_TableAdresse.COL_CommentaireMat[i]
    sdAjouterAdresseClient.PIdFraisPort = TABLE_TableAdresse.COL_IdFraisPort[i]
    sdAjouterAdresseClient.PcomptaDefaut = TABLE_TableAdresse.COL_AdresseDefautCompta[i]
     
    //Utilisation de la PS
    SI HExécuteRequêteSQL(sdAjouterAdresseClient,"gcnxMaConnexion", ...
      hRequêteSansCorrection ,"AjouterAdresseClient @PAdresseClient,@PIdTypeAdresse,@PIdClient,@PIDVille,@PIDPrefix_adresse,@PIDTournee,@PSaisiPar,@PCommentaireLiv,@PCommentaireMat,@PIdFraisPort,@PcomptaDefaut") ALORS	
      //Annulation de la PS pour la prochaine itinération
      HAnnuleDéclaration(sdAjouterAdresseClient)
    SINON
      Erreur(HErreurInfo())
      Info("La partie adresse n'a pas pu être injectée dans la base de données")
    FIN
    Maintenant, je travaille comme ça. Enfin, je maintiens comme ça, je ne commence plus de nouveaux projets en Windev.

    Code : 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
     
    gcnxMaConnexion..Utilisateur = gsDbLogin
    gcnxMaConnexion..MotDePasse = gsDbPassword
    gcnxMaConnexion..Serveur = gsNomServer + "," + gsPortServer
    gcnxMaConnexion..BaseDeDonnées = gsDbName
    gcnxMaConnexion..Provider = hOledbSQLServer
    gcnxMaConnexion..Accès = hOLectureEcriture 
    gcnxMaConnexion..OptionsCurseur = hCurseurClient+hCurseurForwardOnly 
     
    txtReq est une chaîne = "" 
    txtReq = "EXEC [dbo].[User_UpdateTo]  @PNom='"+SAI_Nom+"',@PIdTourOperateur='"+gIdTo+...
    "',@PParite='"+INT_Parite+"',@PImage='"+SC_SelecteurFichier+"',@POrdre='"+SAI_Ordre+"',@PVisible='"+INT_VisibleAvitourTravel+...
    "',@partenaire='"+INT_Partenaire+"',@CouleurSurSite='"+SAI_couleurOk+"',@idCatTo='"+COMBO_IDCatTO..ValeurAffichée+...
    "',@PDateDefautTurnover='"+SAI_Date_Défaut+"',@PNoPDF='"+INT_NOPDF+"',@PSaisiPar='"+gsLoginUtilisateur+"';"
     
    ModifierTo est une Source de Données
     
    SI HExécuteRequêteSQL(ModifierTo,"gcnxMaConnexion", ...
      hRequêteSansCorrection,txtReq) ALORS		
      HLitPremier(ModifierTo)
      TANTQUE PAS HEnDehors(ModifierTo)
        nErreur = ModifierTo.CodeRetour
        HLitSuivant(ModifierTo)
      FIN
      HAnnuleDéclaration(ModifierTo)
    SINON
      Erreur(HErreurInfo())
    FIN
    SI nErreur = 1 ALORS
      Ferme()	
    SINON SI nErreur = 2 ALORS
      Info("L'enregistrement n'a pas pu être ajouté ou modifié ! ")
    SINON SI nErreur = 3 ALORS
      Info("Ce nom est déjà utilisé dans le système. Merci de changer par un autre.")
      RepriseSaisie(SAI_Nom)
    FIN
    Si ça peut aider...

  8. #8
    Membre expérimenté
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2012
    Messages : 162
    Par défaut
    Bonjour à tous,

    L'idée principale était de pouvoir passer des paramètres de type tableau ou de type structure à une procédure stockée, comme par analogie avec un langage de programmation classique comme Windev ou C#.
    J'ai trouvé le moyen de le faire et effectivement cela nécessite l'utilisation des "User-Defined Table Types" avec la génération dynamique de scripts SQL adaptés au besoin.
    Voici un petit exemple d'utilisation réalisé avec Windev et SQL Server:

    Liste des objets de la BD
    1. Création des tables: FACTENT et FACTDET;
      Code sql : 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
       
      CREATE TABLE FACTENT
      (
      	IdFacEnt int IDENTITY(1,1) NOT NULL,
      	NoFacture varchar(15) NOT NULL,
      	LibFacture varchar(50) NOT NULL,
      	MontantHTX numeric(15, 2) NOT NULL,
      	MontantTVA numeric(15, 2) NOT NULL,
      	MontantTTC numeric(15, 2) NOT NULL,
              CONSTRAINT PK_FACTENT PRIMARY KEY (IdFacEnt),
              CONSTRAINT IX_FACTENT UNIQUE (NoFacture)
      )
      GO
       
      CREATE TABLE FACTDET
      (
      	IdFacDet int IDENTITY(1,1) NOT NULL,
      	IdFacEnt int NOT NULL,
      	NumLigne int NOT NULL,
      	LibLigne varchar(50) NOT NULL,
      	MontantHTX numeric(15, 2) NOT NULL,
      	MontantTVA numeric(15, 2) NOT NULL,
      	MontantTTC numeric(15, 2) NOT NULL,
              CONSTRAINT PK_FACTDET PRIMARY KEY (IdFacDet)
      )
      GO
       
      ALTER TABLE FACTDET  WITH CHECK ADD CONSTRAINT FK_FACTDET_FACTENT FOREIGN KEY(IdFacEnt) REFERENCES FACTENT (IdFacEnt)
      GO
       
      ALTER TABLE FACTDET CHECK CONSTRAINT FK_FACTDET_FACTENT
      GO
    2. Création des User-Defined Table Types: UDDT_FACTENT et UDDT_FACTDET;
      Code sql : 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
       
      CREATE TYPE [dbo].[UDDT_FACTENT] AS TABLE(
      	[IdFactEnt] [int] NULL,
      	[NoFacture] [varchar](15) NOT NULL,
      	[LibFacture] [varchar](50) NOT NULL,
      	[MontantHTX] [numeric](15, 2) NOT NULL,
      	[MontantTVA] [numeric](15, 2) NOT NULL,
      	[MontantTTC] [numeric](15, 2) NOT NULL
      )
      GO
       
      CREATE TYPE [dbo].[UDDT_FACTDET] AS TABLE(
      	[IdFactDet] [int] NULL,
      	[IdFactEnt] [int] NULL,
      	[NumLigne] [int] NOT NULL,
      	[LibLigne] [varchar](50) NOT NULL,
      	[MontantHTX] [numeric](15, 2) NOT NULL,
      	[MontantTVA] [numeric](15, 2) NOT NULL,
      	[MontantTTC] [numeric](15, 2) NOT NULL
      )
      GO
    3. Création des procédures stockées: sp_insertfactdet, sp_insertfactent, sp_insertfacture.
      Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
       
      CREATE PROCEDURE [dbo].[sp_insertfactdet]
      (
      	@IdFacEnt INT,
      	@NewFD UDDT_FACTDET READONLY
      )
      AS
      BEGIN
      	SET NOCOUNT ON;
       
      	-- Insertion de l'entête	
      	INSERT INTO FACTDET (IdFacEnt, NumLigne, LibLigne, MontantHTX, MontantTVA, MontantTTC)
      	SELECT @IdFacEnt, FD.NumLigne, FD.LibLigne, FD.MontantHTX, FD.MontantTVA, FD.MontantTTC
      	FROM @NewFD FD
      END

      Code sql : 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
       
      CREATE PROCEDURE [dbo].[sp_insertfactent]
      (
      	@NewFE UDDT_FACTENT READONLY,
      	@IdFacEnt INT OUTPUT
      )
      AS
      BEGIN
      	SET NOCOUNT ON;
       
      	-- Insertion de l'entête	
      	INSERT INTO FACTENT (NoFacture, LibFacture, MontantHTX, MontantTVA, MontantTTC)
      	SELECT FE.NoFacture, FE.LibFacture, FE.MontantHTX, FE.MontantTVA, FE.MontantTTC
      	FROM @NewFE FE
       
      	-- Retour de l'identifiant unique
      	SET @IdFacEnt = @@IDENTITY;	
      END

      Code sql : 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
       
      CREATE PROCEDURE [dbo].[sp_insertfacture]
      (
      	@NewFE UDDT_FACTENT READONLY,
      	@NewFD UDDT_FACTDET READONLY
      )
      AS
      BEGIN
      	SET NOCOUNT ON;
       
      	-- Ajout de l'entête
      	DECLARE @IdFacEnt INT;	
      	EXEC sp_insertfactent @NewFE, @IdFacEnt OUTPUT;
       
      	-- Ajout des détails
      	IF (@IdFacEnt IS NULL) OR (@IdFacEnt = 0)
      		RAISERROR ('Id facture Vide', 12, 1);
      	ELSE
      	BEGIN
      		EXEC sp_insertfactdet @IdFacEnt, @NewFD;
      	END
      END


    Code écrit coté Windev pour la MAJ
    Code : 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
    //Entête de facture
    StructEnteteFA est une Structure
    	IDFacEnt est un entier
    	NoFacture est une chaîne de 15
    	LibFacture est une chaîne de 50
    	MontantHTX est un numérique(18,2)
    	MontantTVA est un numérique(18,2)
    	MontantTTC est un numérique(18,2)
    FIN
    
    //Détail de facture
    StructDetailFA est une Structure
    	IDFacDet est un entier
    	IDFacEnt est un entier
    	NumLigne est un entier
    	LibLigne est une chaîne de 50
    	MontantHTX est un numérique(18,2)
    	MontantTVA est un numérique(18,2)
    	MontantTTC est un numérique(18,2)
    FIN
    
    //Fonction pour la création (La base de donnée a été nommé "BdOfTest")
    FONCTION InsertFacture(LOCAL PPrmsEntete est StructEnteteFA, LOCAL PtaDetails est un tableau de StructDetailFA)
    //Init.
    bResultat est un booléen = Faux
    
    //Traitement
    nNumConnexion est un entier = SQLConnecte(gsNomDuServer, gsUtilisateur, gsLMotDePasse, gsNomDataBase, "OLEDB", hOledbSQLServer, "Trusted_Connection=NO")
    SI (nNumConnexion <> 0) ALORS
    	SQLTransaction(sqlDébut)
    	QUAND EXCEPTION DANS
    		sDetailValues est une chaîne = ""
    		sdfaElement est un StructDetailFA
    		POUR TOUT sdfaElement DE PtaDetails
    			SI (sDetailValues <> "") ALORS sDetailValues += ", " 
    			sDetailValues += ChaîneConstruit("(%1, '%2', %3, %4, %5)", sdfaElement.NumLigne, AjouterQuote(sdfaElement.LibLigne), sdfaElement.MontantHTX, ...
    											 sdfaElement.MontantTVA, sdfaElement.MontantTTC)
    		FIN
    		SI (sDetailValues <> "") ALORS sDetailValues += "; " 
    		sScriptSQLServer est une chaîne =
    		[
    			Use BdOfTest;
    			
    			DECLARE @EnteteFA UDDT_FACTENT;
    			Insert INTO @EnteteFA (NoFacture, LibFacture, MontantHTX, MontantTVA, MontantTTC) VALUES ('%1', '%2', %3, %4, %5);
    			
    			DECLARE @DetailFA UDDT_FACTDET;
    			Insert INTO @DetailFA (NumLigne, LibLigne, MontantHTX, MontantTVA, MontantTTC) VALUES
    		] + sDetailValues + 
    		[
    			
    			EXEC sp_insertfacture @EnteteFA, @DetailFA;
    		]
    		sScriptSQLServer = ChaîneConstruit(sScriptSQLServer, AjouterQuote(PPrmsEntete.NoFacture), AjouterQuote(PPrmsEntete.LibFacture), PPrmsEntete.MontantHTX, ...
    										   PPrmsEntete.MontantTVA, PPrmsEntete.MontantTTC)
    		bResultat = SQLExec(sScriptSQLServer, "SPPPP")
    		SI (PAS bResultat) ALORS
    			SQLInfoGene("SPPPP")
    			SI (EnModeTest() = Vrai) ALORS
    				ExceptionDéclenche(1, SQL.MesErreur)
    			SINON
    				ExceptionDéclenche(1, "Code erreur: " + SQL.Erreur)
    			FIN
    		FIN
    		SQLTransaction(sqlFin)		//Validation de la transaction		
    	FAIRE
    		SQLTransaction(sqlAnnule)	//Annulation de la transaction
    		Erreur(ExceptionInfo())
    	FIN
    SINON
    	//La connexion a échoué : affichage d'un message explicatif
    	SQLInfoGene()
    	Erreur("La connexion à la source de données a échoué." + RC + "Code erreur : " + SQL.Erreur + RC + SQL.MesErreur)
    FIN
    SQLDéconnecte()
    
    //Finalisation
    RENVOYER bResultat
    L'avantage de cette méthode est d'envoyer toutes les données à traiter en une fois au serveur (Traitement par lots), ce qui devrait améliorer la performance. Par conséquent, le débogage devra se faire côté Transact-SQL (ce qui implique une bonne connaissance du langage) .

    En espérant, ce retour d'expérience aura été utile.

    Cordialement.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 12
    Dernier message: 04/05/2015, 13h58
  2. Réponses: 2
    Dernier message: 02/01/2012, 22h23
  3. Taille de stockage maximale des différents types en sql server
    Par stefsas dans le forum Accès aux données
    Réponses: 1
    Dernier message: 02/07/2010, 09h15
  4. Réponses: 0
    Dernier message: 29/03/2010, 16h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo