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 :

Questions Architecture 3 tiers en programmation procédurale, Databinding et structures [WD25]


Sujet :

WinDev

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2020
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Aisne (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2020
    Messages : 66
    Par défaut Questions Architecture 3 tiers en programmation procédurale, Databinding et structures
    Bonjour,

    J'ai un projet de CRM déjà bien avancé. Le problème de ce projet, c'est que le code métier et UI n'ont pas été séparés. J'aimerais donc séparer les codes en utilisant une architecture type 3-tiers avec des structures et procédures. Je ne maitrise pas encore les classes et la POO pour programmer en objet donc je ne souhaite pas m'aventurer dans de la POO surtout que le projet est déjà avancé, même si apparemment c'est le mieux à faire.

    De ce fait, j'aurais besoin d'aide sur certains points qui me bloquent. J'ai bien compris le principe théorique de l'architecture 3 tiers, mais j'ai un peu de mal sur certains points pour l'appliquer dans Windev. Voici mes questions :

    Q1) Dois-je créer une collection de procédure pour CHAQUE table de l'analyse et CHAQUE requête avec la structure et le mapping correspondant ? Exemple Table Contact => créer une collection COL_Contact et une structure globale STCOL_Contact mappé sur ma table Contact ? Pareil pour ma table Société, Civilité, mes requêtes fichiers etc ?


    Q2) Pour une table possédant des clés étrangères. Comment les modéliser dans ma structure ?
    Exemple : Table contact (IDcontact, nom, prénom, IDsociete (clé étrangère de la table Société))
    Dois-je écrire pour ma Structure STCOL_Contact :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IDsociete est un entier
    OU
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    refIDsociete est STCOL_Societe dynamique
    ? J'ai essayer de générer automatiquement mes procédures globales avec mes structures via windev "Modélisation UML > Générer code" et les clés étrangères dans mes structures ont été défini de la façon suivante : refIDsociete est STCOL_Societe dynamique pour reprendre l'exemple ci-dessus. Cependant, quand je fais un fichierversmemoire(), l'IDsociete ne se remplie donc pas automatiquement. Donc dois-je écrire IDCléEtrangères est un entier dans ma structure pour mes clés étrangères ?


    Q3) Pour initialiser une variable tableau de structure STCOL_Contact (ID, Nom, Prénom ...) , dois-je utiliser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tabContact est un tableau de STCOL_Contact
    ou bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tabContact est un tableau de STCOL_Contact DYNAMIQUE
    ? Et que permet le "Dynamique" dans ce cas ?


    Q4) Lorsque j'initialise dans ma fenêtre ma table contact remplie par variable via databinding (sur ma variable tabContact donc), si j'ajoute ou modifie un élément de la table contact, dois-je rafraîchir simplement la table via TableAffiche() ou réexécuter la requête sur la BDD qui me permet de remplir ma variable tabContact et ensuite d'afficher de nouveau ? (Car si je rafraîchi uniquement ma table mémoire via tableaffiche(), les ajouts/modification/suppression entre temps des autres utilisateurs ne seront donc pas visibles sauf si je ferme puis reouvre la fenêtre, est-ce un fonctionnement normal ou faut-il rafraîchir toutes les données à partir de la BDD?)


    Q5) Lorsque je veux modifier une ligne de ma table contact, je souhaite ouvrir une fenêtre pour modifier ma ligne (FEN_GestionContact). Je suppose qu'il faut que je fasse quelque chose de ce type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    pstContactCourant est un STCOL_Contact dynamique
    pstContactCourant = TABLE_Contact
     
    pstContactCourant = Ouvre(FEN_GestionContact,pstContactCourant ) 
    TableAffiche(TABLE_Contact,taCourantBandeau)
    Mais une fois dans ma FEN_GestionContact qui me permet de modifier ma ligne, dois-je faire une recherche sur la BDD à l'initialisation via le paramètre pstContactCourant.IDcontact afin de remplir les champs du contact à modifier ? (Dans le cas où ce contact aurait été modifié entre temps par un autre utilisateur). Ou j'affecte simplement mes champs par databinding via ma variable pstContactCourant passée dans la fenêtre, mais qui n'est donc peut-être plus à jour entre temps ?

    J'ai un peu de mal à saisir quand est-ce que je dois réutiliser la couche données pour mettre à jour mes variables structures.


    Q6) Dans le cas de suppression d'un contact dans ma table TABLE_Contact, est-il possible de supprimer à la fois l'élément dans la table TABLE_Contact ET dans la variable tableau tabContact (lié à la table pour le databinding) ? Car si je fais un TableSupprimeSelect(), l'élément disparaît bien de ma table TABLE_Contact, mais est toujours présent dans mon tableau tabContact. Donc si je fais de nouveau un TableAffiche(), il réapparaît dans la table TABLE_Contact.


    Si certains d'entre-vous auraient des réponses à m'apporter sur les points ci-dessus afin de m'aider à y voir plus claire et me permettre d'avancer, ça serait sympa car là je bloque...

    Merci d'avance,
    Bonne soirée,
    Esteban

  2. #2
    Expert confirmé
    Avatar de Voroltinquo
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Juin 2017
    Messages
    2 958
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Juin 2017
    Messages : 2 958
    Billets dans le blog
    1
    Par défaut
    Bonjour,
    R1) Si ton appli est bien structurée, tu peux très bien continuer avec des accès "Classique" à tes tables. Un contrainte que je m'impose est simplement de coder à minima dans les champs, je fais appel à des procédures/fonctions locale ou globale en fonction de la portée.
    R2) Le fait de déclarer une structure ou un tableau de structure pour "symboliser" tes FK signifie que tu vas remplir ces structures. Dans ton cas lorsque tu va lire un tuple de ta table contact, il faut lire le ou les tuples associés dans la table reliée.
    R3) Comme dans tous les langages, "Dynamique" signifie que nous ne sommes pas dans le cas d'un tableau de taille fixe. Pour utiliser ce genre de tableau, il faut faire une allocation. Une solution de contournement dans Windev est de préciser <agrandissement=taille> lors de la déclaration. Tu pourras ainsi ajouter une ligne à ton tableau de manière "transparente"
    R4)Dans tous les cas il faut ré éxécuter la requête. TableAffiche offre l'option taRéExécuteRequête

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2020
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Aisne (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2020
    Messages : 66
    Par défaut
    Citation Envoyé par Voroltinquo Voir le message
    Bonjour,
    R1) Si ton appli est bien structurée, tu peux très bien continuer avec des accès "Classique" à tes tables. Un contrainte que je m'impose est simplement de coder à minima dans les champs, je fais appel à des procédures/fonctions locale ou globale en fonction de la portée.
    R2) Le fait de déclarer une structure ou un tableau de structure pour "symboliser" tes FK signifie que tu vas remplir ces structures. Dans ton cas lorsque tu va lire un tuple de ta table contact, il faut lire le ou les tuples associés dans la table reliée.
    R3) Comme dans tous les langages, "Dynamique" signifie que nous ne sommes pas dans le cas d'un tableau de taille fixe. Pour utiliser ce genre de tableau, il faut faire une allocation. Une solution de contournement dans Windev est de préciser <agrandissement=taille> lors de la déclaration. Tu pourras ainsi ajouter une ligne à ton tableau de manière "transparente"
    R4)Dans tous les cas il faut ré éxécuter la requête. TableAffiche offre l'option taRéExécuteRequête
    Bonjour, merci pour ton aide

    1) Le problème avec l'accès classique aux tables sans passer par des structures ou classes intermédiaires, c'est qu'il n'y a pas de séparation du code UI et Métier si j'ai bien compris ?
    En gros pour remplir mes champs à l'initialisation d'une fenêtre je vais devoir faire pour la méthode classique sans séparation de couche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Hlitrecherchepremier(Contact,IDcontact,ID) //métier
    si htrouve() //métier
    fichierversecran() //UI
    fin
    et pour remplir mes tables :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    hexecuterequete(mareq,hrequetedefaut,ID) //métier
    pour tout mareq
    tableajouteligne(table_contact,mareq.id,mareq.nom,mareq.prenom) //UI
    fin
    Donc le code UI et métier sont bien mélangés, même si j'utilise une procédure locale pour coder à minima dans ma fenêtre. Cela risque de poser des problèmes sur le long terme non ? Car c'est une grosse appli en devenir, composée de plusieurs modules (CRM, RH etc.) donc même si la CRM (premier module) est actuellement bien avancée, j'aimerais être sur d'avoir un code un minimum "propre" et maintenable sur le long terme, quitte à repartir sur de bonne base s'il est préférable dans ce cas de bien séparer l'UI et le code métier, avant d'attaquer les autres modules et qu'il soit trop tard ensuite pour revenir en arrière...


    2) Dans ce cas, si je souhaite uniquement récupérer l'ID, je n'ai pas besoin de déclarer ma FK comme une structure ? Un simple "IDsociete est un entier" suffit ?


    4) Le problème, c'est que ma table est bindée sur ma variable tableau de structure STCOL_Contact, donc je ne peux pas utiliser le taRéExécuteRequête de tableaffiche(). Et un simple tableaffiche() va simplement mettre à jour la table à partir de ma variable tableau de structure STCOL_Contact qui n'est pas forcément à jour avec les données qui auraient pu être ajoutées/modifiées/supprimées coté serveur.
    Donc si j'ai bien compris, à chaque modification, ajout de contact, je suis obligé d'actualiser toute la table et donc de refaire le traitement coté serveur que je fais à l'initialisation de ma fenêtre pour charger ma table ? C'est à dire rappeler ma procédure globale qui exécute la requête pour récupérer tous mes contacts, qui les affectent à ma variable tableau de structure et qui me renvoie cette variable tableau pour que je puisse faire ensuite un tableaffiche() pour mettre à jour ma table via databinding avec ma variable tableau récupérée ?


    En tout cas merci d'avoir pris le temps de me répondre

  4. #4
    Expert confirmé
    Avatar de Voroltinquo
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Juin 2017
    Messages
    2 958
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Juin 2017
    Messages : 2 958
    Billets dans le blog
    1
    Par défaut
    Tu Peux éventuellement voir du côté du RAD MVP ne serait-ce que pour comprendre le squelette

  5. #5
    Membre émérite
    Homme Profil pro
    Chef de projet
    Inscrit en
    Mars 2017
    Messages
    343
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Chef de projet
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2017
    Messages : 343
    Par défaut
    Q1-En objet chaque table à sa classe quand on procède avec le pattern ORM, qui contient dans ses attributs toutes les rubriques de la table. C'est ce que tu proposes de faire en remplacant la classe par une collection de procédure et ses attributs par une structure. L'approche est bonne mais n'oublie pas qu'à chaque mise à jour de l'analyse, tes structures et toutes les procédures crées seront possiblement à contrôler si Windev n'en permet pas la génération (je n'ai pas utilisé de modèle UML jusque là donc je ne connais pas les capacités de génération de Windev dans ce cas). Est-ce que tu dois? Non. Comme le dit Voroltinquo, ça n'est pas obligatoire si ton projet est structuré et je ne peux qu'appuyer son argument: rien derrière les éléments de l'IHM, c'est un vrai carnage ensuite pour la factorisation du code et sonn nettoyage. Tout doit être encapsulé dans des procédures locales/globales
    Je dirais quand même que l'usage de la POO avec du databinding Fichier-Classe (fonctions FichierVersMémoire/MémoireVersFichier ou FichierVersTableau) ira bien pour des volumes de données faibles, mais si les volumes augmentent, l'objet se révèlera bien lent; il en va de même pour les structures. Tout charger en mémoire n'est pas systématiquement une bonne idée surtout si l'application fonctionne avec une base distante.
    Le FichierVersEcran, ce n'est pas incompatible avec un code propre si c'est bien utilisé dans les procédures adéquates (locales, en conjugaison avec le traitement "Demande de mise à jour de l'affichage" de la fenêtre). Néanmoins, je préfère bannir cette instruction et passer par des variables en mémoire qui sont chargées avec la base, car le FichierVersEcran lie la couche données à la couche présentation, ce qui n'est pas vraiment du 3 tiers. Il manque un tiers : le traitement, censé encapsuler les codes métiers.

    Q2-Il est préférable que les clés étrangères (les FK) soient identifiées. Quand je conçois les bases elles sont préfixées IDX et se retrouvent nommée m_IDX dans les objets, mais en procédural il est possible en effet de leur donner un nom qui est formatté et qui indique bien que c'est une clé étrangère donc les préfixer de ref est une bonnée idée. Quand à ce que dit Voroltinquo, le fait de charger un objet X qui contient la clé étrangère de Y n'implique pas forcément de charger Y. En fait, cela dépend des cas. Je sais que parfois dans mon code je n'aurais pas besoin de charger l'ensemble des objets liés donc je ne le faisais que si c'est nécessaire en instanciant un objet à part. C'était une ancienne méthode que j'utilisais. Plus tard, j'ai utilisé des JOIN dans les requêtes ce qui rendait les temps de chargement tellement court que chaque objet unitaire était systématiquement chargé dans son parent, même si c'était désactivable. Pour les éléments multiples (la liste des factures d'un client) ce sont des tableaux dont le chargement n'était fait qu'à la demande car c'est long à requêter.
    Donc écrire directement refIDsociete est STCOL_Societe dynamique, je tiques un peu. refIDSociete n'est pas un STCOL_Societe mais un entier dans la base. STCOL_Societe c'est la représentation par code de cette table, ça ne désigne pas tout à fait la même chose. Quand tu coderas, tu devras prévoir de quoi charger ces objets, c'est une surcharge qui ne servira peut être pas toujours comme je l'expliques plus haut. Je ferais donc comme tu le dis dans ton deuxième message: refIDSociete est un entier.


    Q3-Dynamique en objet c'est déclarer un objet sans l'allouer. Ne pas préciser dynamique c'est en fait instancier l'objet sans qu'on l'ai explicitement demandé et donc il occupera de la place en mémoire dès la déclaration. Alors que si on le déclare dynamique il faudra faire une autre ligne de code pour l'allouer.
    Néanmoins, ta question soulève un point auquel je ne sais pas répondre et je l'ai donc testé sous WD25:

    Ce code
    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
     
    stStruct est une Structure
    	nom est chaîne
    	prenom est une chaîne
    	agee est entier
    FIN
     
    oSt est une stStruct dynamique
    oST2 est une stStruct
     
    tabST est un tableau de stStruct dynamique
    tabST2 est un tableau dynamique de stStruct
     
    TableauAjoute(tabST,oSt)
    TableauAjoute(tabST2,oST2)

    Compile et s'execute. Au débuggeur, tabST contient un élément mais comme oST est dynamique cet élément vaut NULL, alors que oST2 dans son tableau tabST2 ne vaut pas Null: il est bien vivant en mémoire et possède les valeurs par défaut de ses types de données (2 chaines vide et 0 dans l'entier)

    Si tu remplaces
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tabST2 est un tableau dynamique de stStruct
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tabST2 est un tableau de stStruct
    le code fonctionne encore. D'après la doc (https://doc.pcsoft.fr/fr-FR/?1514057) , ce sont 2 écritures identiques: "Il est conseillé d'utiliser : Un tableau dynamique ou un tableau "simple" lorsque la taille du tableau doit être modifiée au cours du programme". Donc je n'utilises que des tableaux simples. Et à ta place je mettrais donc tabContact est un tableau de STCOL_Contact: le tableau sera vide, pourra être agrandi via TableauAjoute, mais uniquement par des éléments qui de toute façon vont exister (des STCol_Contact) et qui pourront être dynamiques ou pas: tu devras forcément les instancier pour qu'ils contiennent quelque chose. Ajouter une structure dynamique à un tableau ne fonctionne pas: si tu fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TableauAjoute(tabST2 ,oSt)
    Windev crash en te disant "Vous avez appelé la fonction TableauAjoute. L'objet à affecter n'est pas alloué."

    Q4-Penses bien à segmenter où sont les données dans ta tête: si un autre modifie la base, tu ne verras rien chez toi tant que tu n'auras pas réexécuté la requête car les données que tu affiches viennent du databinding d'un tableau en mémoire, donc viennent de la mémoire. La mémoire n'est pas forcément à jour de la BDD. Si quand tu ouvres la fenêtre tu fais un chargement de tabContact depuis la BDD mais qu'ensuite tu ne requêtes plus la BDD, tu ne verras jamais les modifs des autres. Donc quand tu veux rafraichir, requêtes la base comme dit Voroltinquo (et attention aux SELECT *....si tu commences à avoir beaucoup de données, ça va devenir lent.), afin de mettre le contenu de la base (le tier données) dans la structure en mémoire (le tiers traitement) pour les afficher ensuite à l'écran (le tiers présentation). Comme tu le dis, à chaque requête, tu recharges tout. Tu vois donc les limites de ce modèle que j'explique plus haut: si t'as une table de 5000 lignes, tu vas tout prendre dans la tête en mémoire, avec le temps de traitement qui va avec.

    Q5-Y'a 2 approches: soit ta structure contient déjà tout et tu demande à la fenêtre d'afficher la structure en mémoire, soit tu passes l'ID à la fenêtre et tu demandes à la fenêtre de charger elle même l'élément à modifier. Je préfère cette deuxième approche ne serait-ce que pour le cas d'une appli fortement concurentielle (c'est à dire une appli utilisée en même temps par beaucoup d'utilisateurs). Charger une seule structure via un ID est très rapide, autant donc le faire au dernier moment pour avoir la donnée la plus à jour possible.

    Q6-TableSupprimeSelect() ne touche pas à la variable databindée. Fais l'inverse: quand le tier présentation demande au tiers traitement de supprimer une donnée, supprimes la dans ta variable mémoire (c'est le tier traitement qui fait la suppression dans sa propre couche), répercutes ça dans la base et réaffiche ton IHM: soit en direct depuis la mémoire sans récupérer depuis la base, soit en éxécutant la requête à nouveau pour remplir la mémoire, et l'IHM à partir de la mémoire.

  6. #6
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2020
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Aisne (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2020
    Messages : 66
    Par défaut
    Merci à vous deux pour vos réponses et explications

    Citation Envoyé par kunnskap Voir le message
    Q1-En objet chaque table à sa classe quand on procède avec le pattern ORM, qui contient dans ses attributs toutes les rubriques de la table. C'est ce que tu proposes de faire en remplacant la classe par une collection de procédure et ses attributs par une structure. L'approche est bonne mais n'oublie pas qu'à chaque mise à jour de l'analyse, tes structures et toutes les procédures crées seront possiblement à contrôler si Windev n'en permet pas la génération (je n'ai pas utilisé de modèle UML jusque là donc je ne connais pas les capacités de génération de Windev dans ce cas). Est-ce que tu dois? Non. Comme le dit Voroltinquo, ça n'est pas obligatoire si ton projet est structuré et je ne peux qu'appuyer son argument: rien derrière les éléments de l'IHM, c'est un vrai carnage ensuite pour la factorisation du code et sonn nettoyage. Tout doit être encapsulé dans des procédures locales/globales
    Je dirais quand même que l'usage de la POO avec du databinding Fichier-Classe (fonctions FichierVersMémoire/MémoireVersFichier ou FichierVersTableau) ira bien pour des volumes de données faibles, mais si les volumes augmentent, l'objet se révèlera bien lent; il en va de même pour les structures. Tout charger en mémoire n'est pas systématiquement une bonne idée surtout si l'application fonctionne avec une base distante.
    Le FichierVersEcran, ce n'est pas incompatible avec un code propre si c'est bien utilisé dans les procédures adéquates (locales, en conjugaison avec le traitement "Demande de mise à jour de l'affichage" de la fenêtre). Néanmoins, je préfère bannir cette instruction et passer par des variables en mémoire qui sont chargées avec la base, car le FichierVersEcran lie la couche données à la couche présentation, ce qui n'est pas vraiment du 3 tiers. Il manque un tiers : le traitement, censé encapsuler les codes métiers.
    Juste pour être dans le contexte, le projet que je développe est un projet sur plusieurs modules, le premier étant une CRM avec gestion de contact, sociétés, opportunités, offres, etc avec possibilité de recherche. Sur une fiche contact, on a plusieurs onglets, avec par exemple les familles de produits pour ce contact, les moyens de communication etc. Ce sont des tables mémoires avec bouton ajouter, modifier, supprimer pour chacune des tables. (Le bouton ajout/modif ouvre la fiche de la table correspondante). Il n’y aura normalement jamais 5000 enregistrements d’un coup à afficher pour une même table. (Sauf lors de la recherche d’un contact si on décide d’ouvrir la table complète des contacts, sans utiliser de filtre par exemple)

    En effet, ça serait un pattern ORM. D’après ce que j’ai vu dans Windev, il est possible de générer la classe (et la régénérer par la suite si modification dans l’analyse pour mettre à jour le mapping) en cliquant dessus > « Générer le modèle de classe ». On a alors une classe mappé sur le fichier et chaque attribut est mappé sur la rubrique de la table. C’est un peu le principe du RAD MVP que ma conseillé Voroltinquo, il génère la classe modèle de la sorte pour les fichiers de l’analyse et en prime une classe TableauDeLaClasseGénérée qui possède un attribut « *** est un tableau de LaClasseGénérée dynamique » avec une méthode Charger (pour charger les éléments dans le tableau mémoire via requête), une méthode Ajouter (Pour ajouter un élément au tableau mémoire par la suite) et une méthode Supprimer. Il y a également une classe de base MBase dont toutes les classes héritent et qui possèdes les méthodes d’ajout, de modification, et de suppression d’éléments dans la BDD. (MemoireVersFichier() > Hajoute / Hmodifie)
    Le principe a l’air bien, mais je ne souhaite pas utiliser un pattern MVP, du moins je préfère continuer de programmer la couche Présentation avec des procédures locales/globales plutôt qu’utiliser des classes présentations que je trouve assez complexe.

    Q1) En gros pour de l’ORM, je devrais générer la classe modèle de la table avec le mapping, ET une classe TableauDeCetteClasse pour récupérer les éléments de ma table ? Et ça pour chacune des tables de mon analyse ?
    Q2) Et concernant mes requêtes qui récupèrent des éléments sur plusieurs tables ? Je devrais également créer une classe avec les attributs de cette requête pour pouvoir les databinder sur ma table visuelle ?
    Q3) J’ai également une recherche avancée, où j’ai plein de critères de recherche, je ne peux donc pas prévoir d’avance mes attributs, ni le nombre d’éléments à charger. Je suppose que pour ma fonctionnalité recherche avancée, je ne pourrais pas faire du 3 tiers au risque de perdre en performance ?


    Le truc c’est comme tu dis, le fichierversecran lie la couche donnée et présentation, je souhaitais justement avoir un tiers intermédiaire traitement, d’où ma demande sur ce pattern ORM. Étant donné que tu dis bannir également cette instruction, tu utilises donc également l’architecture 3 tiers avec le databinding sur les classes et ce pattern ORM ?


    Citation Envoyé par kunnskap Voir le message
    Q2-Il est préférable que les clés étrangères (les FK) soient identifiées. Quand je conçois les bases elles sont préfixées IDX et se retrouvent nommée m_IDX dans les objets, mais en procédural il est possible en effet de leur donner un nom qui est formatté et qui indique bien que c'est une clé étrangère donc les préfixer de ref est une bonnée idée. Quand à ce que dit Voroltinquo, le fait de charger un objet X qui contient la clé étrangère de Y n'implique pas forcément de charger Y. En fait, cela dépend des cas. Je sais que parfois dans mon code je n'aurais pas besoin de charger l'ensemble des objets liés donc je ne le faisais que si c'est nécessaire en instanciant un objet à part. C'était une ancienne méthode que j'utilisais. Plus tard, j'ai utilisé des JOIN dans les requêtes ce qui rendait les temps de chargement tellement court que chaque objet unitaire était systématiquement chargé dans son parent, même si c'était désactivable. Pour les éléments multiples (la liste des factures d'un client) ce sont des tableaux dont le chargement n'était fait qu'à la demande car c'est long à requêter.
    Donc écrire directement refIDsociete est STCOL_Societe dynamique, je tiques un peu. refIDSociete n'est pas un STCOL_Societe mais un entier dans la base. STCOL_Societe c'est la représentation par code de cette table, ça ne désigne pas tout à fait la même chose. Quand tu coderas, tu devras prévoir de quoi charger ces objets, c'est une surcharge qui ne servira peut être pas toujours comme je l'expliques plus haut. Je ferais donc comme tu le dis dans ton deuxième message: refIDSociete est un entier.
    Le mieux étant donc d’écrire refIDSociete est un entier et de générer la classe société à part au besoin ? Je prends note, mes clés étrangères sont identifiés par la génération de la classe quoi qu’il arrive étant donné que j’utilise des préfixes dans mes tables de l’analyse qui identifie la table en question.


    Citation Envoyé par kunnskap Voir le message
    Q3-Dynamique en objet c'est déclarer un objet sans l'allouer. Ne pas préciser dynamique c'est en fait instancier l'objet sans qu'on l'ai explicitement demandé et donc il occupera de la place en mémoire dès la déclaration. Alors que si on le déclare dynamique il faudra faire une autre ligne de code pour l'allouer.
    Néanmoins, ta question soulève un point auquel je ne sais pas répondre et je l'ai donc testé sous WD25:

    Ce code
    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
     
    stStruct est une Structure
    	nom est chaîne
    	prenom est une chaîne
    	agee est entier
    FIN
     
    oSt est une stStruct dynamique
    oST2 est une stStruct
     
    tabST est un tableau de stStruct dynamique
    tabST2 est un tableau dynamique de stStruct
     
    TableauAjoute(tabST,oSt)
    TableauAjoute(tabST2,oST2)

    Compile et s'execute. Au débuggeur, tabST contient un élément mais comme oST est dynamique cet élément vaut NULL, alors que oST2 dans son tableau tabST2 ne vaut pas Null: il est bien vivant en mémoire et possède les valeurs par défaut de ses types de données (2 chaines vide et 0 dans l'entier)

    Si tu remplaces
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tabST2 est un tableau dynamique de stStruct
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tabST2 est un tableau de stStruct
    le code fonctionne encore. D'après la doc (https://doc.pcsoft.fr/fr-FR/?1514057) , ce sont 2 écritures identiques: "Il est conseillé d'utiliser : Un tableau dynamique ou un tableau "simple" lorsque la taille du tableau doit être modifiée au cours du programme". Donc je n'utilises que des tableaux simples. Et à ta place je mettrais donc tabContact est un tableau de STCOL_Contact: le tableau sera vide, pourra être agrandi via TableauAjoute, mais uniquement par des éléments qui de toute façon vont exister (des STCol_Contact) et qui pourront être dynamiques ou pas: tu devras forcément les instancier pour qu'ils contiennent quelque chose. Ajouter une structure dynamique à un tableau ne fonctionne pas: si tu fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TableauAjoute(tabST2 ,oSt)
    Windev crash en te disant "Vous avez appelé la fonction TableauAjoute. L'objet à affecter n'est pas alloué."
    Merci pour les explications, je testerais également de mon côté pour que ça soit encore plus claire


    Citation Envoyé par kunnskap Voir le message
    Q4-Penses bien à segmenter où sont les données dans ta tête: si un autre modifie la base, tu ne verras rien chez toi tant que tu n'auras pas réexécuté la requête car les données que tu affiches viennent du databinding d'un tableau en mémoire, donc viennent de la mémoire. La mémoire n'est pas forcément à jour de la BDD. Si quand tu ouvres la fenêtre tu fais un chargement de tabContact depuis la BDD mais qu'ensuite tu ne requêtes plus la BDD, tu ne verras jamais les modifs des autres. Donc quand tu veux rafraichir, requêtes la base comme dit Voroltinquo (et attention aux SELECT *....si tu commences à avoir beaucoup de données, ça va devenir lent.), afin de mettre le contenu de la base (le tier données) dans la structure en mémoire (le tiers traitement) pour les afficher ensuite à l'écran (le tiers présentation). Comme tu le dis, à chaque requête, tu recharges tout. Tu vois donc les limites de ce modèle que j'explique plus haut: si t'as une table de 5000 lignes, tu vas tout prendre dans la tête en mémoire, avec le temps de traitement qui va avec.
    Oui j’ai bien compris que pour récupérer les données qui auraient été ajoutées par les autres utilisateurs, il faudrait que je requête la base pour mettre le contenu dans la classe puis ensuite afficher à l’écran par databinding.
    Mais la question, pour reprendre le contexte de mon projet où j’ai par exemple la table communication sur une fiche contact. Si j’ajoute un moyen de communication pour ce contact, dois-je nécessairement requeter la base ensuite afin de rafraîchir les possibles modifs extérieures ou un simple ajout de ma ligne dans ma classe mémoire + tableaffiche() serait plus logique ? Vu que je peux actualiser la fiche du contact avec un bouton Actualiser qui cette fois-ci rafraîchirait tout.
    En gros lors d’un ajout ou d’une modification d’une ligne d’une table (Communication, famille produits etc) de ma fiche contact, est-ce plus logique d’ajouter simplement la ligne que je viens de créer (comme un tableajouteligne()) plutôt que rafraichir toute la table via requête sur le serveur ? Ou c’est mieux d’utiliser un bouton actualiser qui actualiserait toutes les données extérieures, comme lors du chargement de la fiche du contact à l’ouverture.
    Car le but d'utiliser des variables mémoires, c'est pas aussi justement d'éviter de faire trop de requêtes sur le serveur et de ce fait travailler le plus possible sur les tableaux mémoires générés sans avoir à les rafraîchir à chaque ajout/modifs ?


    Citation Envoyé par kunnskap Voir le message
    Q5-Y'a 2 approches: soit ta structure contient déjà tout et tu demande à la fenêtre d'afficher la structure en mémoire, soit tu passes l'ID à la fenêtre et tu demandes à la fenêtre de charger elle même l'élément à modifier. Je préfère cette deuxième approche ne serait-ce que pour le cas d'une appli fortement concurentielle (c'est à dire une appli utilisée en même temps par beaucoup d'utilisateurs). Charger une seule structure via un ID est très rapide, autant donc le faire au dernier moment pour avoir la donnée la plus à jour possible.
    Actuellement c’est ce que je fais, je passe l’ID dans ma fenêtre pour afficher les données de la ligne à modifier. A la validation, je rafraichis toute la table via tableaffiche(table,tareexecuterequete) (vu que je n’utilise pas encore d’architecture 3 tiers).
    Mais j’ai vu dans l’exemple Initiation au MVP de windev qu’eux passaient l’objet dans la fenêtre pour les modifications et lors d’un ajout, ajoutaient simplement l’élément au tableau mémoire + tableaffiche(), donc pas de rafraichissement totale de la table via requête sur le serveur. C’est pour cela que je me demande quel est vraiment le meilleur principe à utiliser et il y a-t-il un réel intérêt à rafraichir tout via requête sur bdd à chaque ajout / modif d’élément.


    Citation Envoyé par kunnskap Voir le message
    Q6-TableSupprimeSelect() ne touche pas à la variable databindée. Fais l'inverse: quand le tier présentation demande au tiers traitement de supprimer une donnée, supprimes la dans ta variable mémoire (c'est le tier traitement qui fait la suppression dans sa propre couche), répercutes ça dans la base et réaffiche ton IHM: soit en direct depuis la mémoire sans récupérer depuis la base, soit en éxécutant la requête à nouveau pour remplir la mémoire, et l'IHM à partir de la mémoire.
    En effet, c'est plus logique dans ce sens !


    Cordialement,
    Esteban

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

Discussions similaires

  1. Question sur l'architecture trois tiers
    Par sheridan08 dans le forum Plateformes (Java EE, Jakarta EE, Spring) et Serveurs
    Réponses: 10
    Dernier message: 19/06/2013, 14h10
  2. [Débutant] [Question] Architecture n-tiers et patern MVVM
    Par quentin869 dans le forum C#
    Réponses: 5
    Dernier message: 14/06/2013, 19h16
  3. Génération de code, architecture 3 tiers et databinding avancé
    Par neo.51 dans le forum Général Dotnet
    Réponses: 56
    Dernier message: 25/11/2008, 12h05
  4. Question de pointeur entre un programme et une DLL
    Par Neilos dans le forum C++Builder
    Réponses: 12
    Dernier message: 01/02/2005, 19h12
  5. [Design Patterns] Architecture 3 tiers
    Par HPJ dans le forum Design Patterns
    Réponses: 1
    Dernier message: 29/07/2003, 11h49

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