📖 Guides · Conceptuel · ORM_CSHX2

Modes MetaData

Le composant ORM_CSHX2 propose trois modes MetaData qui définissent où résident physiquement les colonnes framework et comment l'ORM les accède.
Ce guide compare les trois modes et donne les critères de choix selon le contexte projet.

01

🗺️ Vue d'ensemble

Le composant ORM_CSHX2 gère automatiquement un ensemble de colonnes transverses — dites colonnes framework — présentes sur chaque table métier. Ces colonnes assurent la traçabilité, le verrouillage applicatif, l'horodatage et la synchronisation inter-bases.

Les colonnes framework gérées sont :

ColonneRôle
SQL_UUIDIdentifiant universel unique de l'enregistrement
SQL_ID_USER_INSERTID utilisateur ayant créé l'enregistrement
SQL_ID_USER_UPDATEID utilisateur ayant modifié l'enregistrement en dernier
SQL_IP_USERPoste de travail de l'utilisateur
SQL_LOCKEDVerrou applicatif (booléen)
SQL_INSERTEDHorodatage de création
SQL_UPDATEDHorodatage de dernière modification
SQL_EXENom de l'exécutable appelant
SQL_PROCEDURE_INSERTProcédure appelante lors de la création
SQL_PROCEDURE_UPDATEProcédure appelante lors de la mise à jour
SQL_STATUSStatut applicatif de l'enregistrement

Le mode MetaData détermine ces colonnes résident physiquement et comment l'ORM les accède. Ce choix est global — configuré une seule fois au démarrage de l'application avant tout appel ORM.

Mode 1
METADATA_MODE_STANDARD
Les colonnes framework sont déclarées dans l'analyse WinDev et créées dans chaque table métier via l'analyse HFSQL.
Mode 2
METADATA_MODE_SQL_ONLY
Les colonnes framework existent physiquement en base SQL mais sont absentes de l'analyse WinDev. L'ORM les injecte manuellement.
Mode 3
METADATA_MODE_JOIN
Les colonnes framework sont centralisées dans une table dédiée cshx2_metadata, accessible via LEFT JOIN. Les tables métier n'ont aucune colonne framework.
02

🔑 Pourquoi des constantes ?

Les colonnes framework sont référencées dans le code via des constantes WLangage dont la valeur est identique au nom :

SQL_UUID = "SQL_UUID" SQL_ID_USER_INSERT = "SQL_ID_USER_INSERT" SQL_ID_USER_UPDATE = "SQL_ID_USER_UPDATE" SQL_IP_USER = "SQL_IP_USER" SQL_LOCKED = "SQL_LOCKED" SQL_INSERTED = "SQL_INSERTED" SQL_UPDATED = "SQL_UPDATED" SQL_EXE = "SQL_EXE" SQL_PROCEDURE_INSERT = "SQL_PROCEDURE_INSERT" SQL_PROCEDURE_UPDATE = "SQL_PROCEDURE_UPDATE" SQL_STATUS = "SQL_STATUS"

Ce pattern peut sembler redondant à première vue. Il répond en réalité à cinq besoins distincts qui se cumulent.

1 — Accès dynamique aux membres de classe via indirection

WLangage permet l'accès indirect à un membre d'objet par son nom via la syntaxe {":" + sMembre, indVariable}. Les constantes rendent possible la construction de ce chemin d'accès de façon fiable et sans magic string :

// Formatage d'une valeur framework — le type est résolu dynamiquement // SQL_INSERTED est une constante = "SQL_INSERTED" // Le membre de classe correspondant est m_dhSQL_INSERTED (DateHeure) SELON Majuscule(sColonne) CAS SQL_INSERTED, SQL_UPDATED nTypeHF = hRubDateHeure CAS SQL_UUID, SQL_IP_USER, SQL_EXE nTypeHF = hRubCaractère CAS SQL_LOCKED nTypeHF = hRubBooléen FIN // Construction du nom de membre par concaténation avec le préfixe de type sNomMembre = "m_dh" + SQL_UPDATED → "m_dhSQL_UPDATED" sValeur = {":" + sNomMembre, indVariable} ← accès indirect au membre

2 — Adaptation à une base de données existante

C'est l'un des cas d'usage les plus concrets. Lorsque le composant est déployé sur une base de données existante dont les colonnes techniques ont déjà des noms différents de la convention framework, l'adaptation se fait sans modifier une seule ligne de code applicatif.

Le mécanisme est exposé via la sous-structure MetadataColumns de ST_ORM_Config au moment de l'initialisation du composant. Chaque colonne framework peut être surchargée par son nom réel dans la base cible :

// Base existante avec ses propres conventions de nommage : // DATE_CREATION au lieu de SQL_INSERTED // DATE_MODIFICATION au lieu de SQL_UPDATED // VERROU au lieu de SQL_LOCKED // GUID_LIGNE au lieu de SQL_UUID stConfig est un ST_ORM_Config // 🏷️ Personnalisation des noms de colonnes framework stConfig.MetadataColumns.sINSERTED = "DATE_CREATION" stConfig.MetadataColumns.sUPDATED = "DATE_MODIFICATION" stConfig.MetadataColumns.sLOCKED = "VERROU" stConfig.MetadataColumns.sUUID = "GUID_LIGNE" // Tout le code ORM s'adapte automatiquement aux noms réels : // - les requêtes SELECT projettent les bons noms de colonnes // - les INSERT et UPDATE écrivent dans les bonnes colonnes // - les comparaisons internes utilisent les noms réels (bOK, nCode, sMsg) = ORM_Setup(stConfig)
⚠️ Incompatibilité avec le mode JOIN

Cette personnalisation est incompatible avec METADATA_MODE_JOIN. Voir ORM_Setup pour les détails.

Sans ce mécanisme de constantes, une reprise de base existante imposerait de rechercher et remplacer les noms de colonnes dans l'intégralité du code ORM — plusieurs centaines d'occurrences réparties sur des dizaines de méthodes. Avec les constantes, la redéclaration est le seul point de contact entre la convention framework et la réalité de la base cible.

ℹ️ Valeur = nom par défaut : un choix délibéré

Dans le cas nominal (nouveau projet), la valeur de la constante est identique à son nom (SQL_UUID = "SQL_UUID"). Cela garantit que le nom de la colonne SQL physique correspond exactement au nom WLangage — un seul référentiel, aucune couche de traduction. La divergence valeur/nom n'intervient que lors d'une adaptation à une base existante, et uniquement pour les constantes concernées.

03

🔵 METADATA_MODE_STANDARD = 1

C'est le mode historique du composant. Les colonnes framework sont déclarées dans l'analyse WinDev (fichier .WDD) et créées physiquement dans chaque table métier par ORM_CheckDataBase(). L'ORM les lit et les écrit directement via le mapping HFSQL standard — aucun traitement spécifique n'est requis.

Table ARTICLE ├── ID_ARTICLE (clé primaire) ├── CODE_ARTICLE ├── LIBELLE ├── SQL_UUID ← colonne framework (déclarée dans l'analyse) ├── SQL_LOCKED ← colonne framework ├── SQL_INSERTED ← colonne framework └── ... ← autres colonnes framework // Idem sur chaque table métier du projet Table COMMANDE ├── ID_COMMANDE ├── ... ├── SQL_UUID └── SQL_LOCKED
✅ Avantages
  • Simplicité maximale — aucune logique spécifique dans l'ORM
  • Compatible HFSQL natif — les colonnes sont visibles dans l'éditeur WinDev
  • Pas de JOIN supplémentaire — performances SELECT optimales
  • Débogage facile — colonnes directement interrogeables
  • Mode de référence — tous les autres modes en dérivent
❌ Inconvénients
  • Duplication des colonnes framework sur chaque table — espace disque multiplié
  • Modification du schéma framework (ajout de colonne) implique un ALTER TABLE sur toutes les tables
  • Analyse WinDev volumineuse — chaque table déclare des colonnes supplémentaires
  • Risque de désynchronisation entre l'analyse et la base si ORM_CheckDataBase() n'est pas appelé
04

🟠 METADATA_MODE_SQL_ONLY = 2

Ce mode est une variante du mode Standard : les colonnes framework existent physiquement dans chaque table SQL, mais elles ne sont pas déclarées dans l'analyse WinDev. L'ORM les détecte dynamiquement au premier accès et les injecte manuellement dans les requêtes INSERT et UPDATE.

Base SQL (physique) Table ARTICLE ├── ID_ARTICLE ├── CODE_ARTICLE ├── LIBELLE ├── SQL_UUID ← présente en base SQL └── SQL_LOCKED ← présente en base SQL Analyse WinDev (.WDD) Table ARTICLE ├── ID_ARTICLE ├── CODE_ARTICLE └── LIBELLE ← colonnes framework ABSENTES de l'analyse // L'ORM détecte l'écart automatiquement à la première instanciation // et injecte les colonnes framework manquantes dans les requêtes SQL
✅ Avantages
  • Analyse WinDev allégée — pas de colonnes framework à déclarer
  • Indépendance entre schéma SQL et analyse WinDev — évolution du framework sans retouche de l'analyse
  • Pas de JOIN supplémentaire — performances SELECT identiques au Mode 1
  • Idéal pour les bases SQL existantes où les colonnes framework ont été ajoutées manuellement
❌ Inconvénients
  • Complexité ORM accrue — détection dynamique des colonnes manquantes à chaque démarrage
  • Colonnes framework invisibles dans l'éditeur WinDev — pas d'autocomplétion
  • Duplication persistante sur chaque table SQL — même problème d'espace disque que le Mode 1
  • Risque d'oubli d'ajout des colonnes framework sur une nouvelle table si l'injection automatique n'est pas effectuée
05

🟣 METADATA_MODE_JOIN = 3

C'est le mode le plus avancé. Les colonnes framework sont centralisées dans une table dédiée cshx2_metadata (TABLE_SQL + ID_TABLE_SQL + colonnes framework). Les tables métier ne contiennent aucune colonne framework — elles sont récupérées à la lecture via un LEFT JOIN sur cshx2_metadata et écrites/mises à jour de manière transparente par l'ORM.

Tables métier (sans colonnes framework) Table ARTICLE Table COMMANDE ├── ID_ARTICLE ├── ID_COMMANDE ├── CODE_ARTICLE ├── DATE_COMMANDE └── LIBELLE └── ID_CLIENT Table cshx2_metadata (centralisée) ├── TABLE_SQL ← "ARTICLE" ou "COMMANDE" ├── ID_TABLE_SQL ← clé primaire de l'enregistrement ├── SQL_UUID ├── SQL_LOCKED ├── SQL_INSERTED └── ... ← toutes les colonnes framework // SELECT avec LEFT JOIN automatique construit par l'ORM SELECT ARTICLE.*, cshx2_metadata.SQL_UUID, cshx2_metadata.SQL_LOCKED, ... FROM ARTICLE LEFT JOIN cshx2_metadata ON cshx2_metadata.TABLE_SQL = 'ARTICLE' AND cshx2_metadata.ID_TABLE_SQL = ARTICLE.ID_ARTICLE
✅ Avantages
  • Schéma métier épuré — tables sans colonnes techniques parasites
  • Évolution du framework centralisée — ajouter une colonne framework = un seul ALTER TABLE cshx2_metadata
  • Analyse WinDev propre — aucune colonne framework à déclarer dans les tables métier
  • Compatible avec des bases SQL tierces où on ne peut pas ajouter de colonnes
  • Historisation facilitée — cshx2_metadata peut être archivée indépendamment
❌ Inconvénients
  • Complexité ORM maximale — LEFT JOIN systématique sur chaque SELECT
  • Performance dégradée sur les SELECT — coût du JOIN, surtout sur les grandes tables
  • INSERT batch non supporté — incompatible avec les insertions multi-lignes (IDs non récupérables en masse)
  • Membres framework obligatoires dans les classes métier — déclaration manuelle requise
  • Index unique obligatoire sur la table cshx2_metadata
  • PostgreSQL : contrainte FOR UPDATE OF uniquement sur la table non-nullable du LEFT JOIN
⚠️ Contrainte INSERT batch

En mode METADATA_MODE_JOIN, mth_EnregistrerTableau() ne peut pas utiliser le batch multi-lignes car les IDs auto-générés ne sont pas récupérables en masse — la ligne cshx2_metadata ne peut pas être créée sans connaître l'ID. Utiliser mth_Enregistrer() individuel à la place.

06

📊 Comparaison des modes

Critère Mode 1 — STANDARD Mode 2 — SQL_ONLY Mode 3 — JOIN
Colonnes framework dans l'analyse WinDev ✅ Oui ❌ Non ❌ Non
Colonnes framework dans les tables métier ✅ Oui ✅ Oui ❌ Non
Table cshx2_metadata dédiée ❌ Non ❌ Non ✅ Oui
LEFT JOIN automatique sur SELECT ✅ Aucun ✅ Aucun ⚠️ Systématique
Performance SELECT ✅ Optimale ✅ Optimale ⚠️ Dégradée (JOIN)
INSERT batch supporté ✅ Oui ✅ Oui ❌ Non
Évolution schéma framework ⚠️ ALTER sur toutes les tables ⚠️ ALTER sur toutes les tables ✅ Un seul ALTER TABLE cshx2_metadata
Propreté du schéma métier ⚠️ Colonnes techniques visibles ⚠️ Colonnes techniques en base ✅ Tables métier épurées
Complexité ORM ✅ Minimale ⚠️ Détection dynamique ❌ Maximale
Compatible base SQL tierce (sans ajout colonne) ❌ Non ❌ Non ✅ Oui
Déclaration membres framework dans les classes ✅ Automatique (analyse) ✅ Automatique (analyse) ⚠️ Manuelle obligatoire
07

🎯 Quel mode choisir ?

Nouveau projet, base créée par l'ORM, pas de contrainte particulière
Mode 1 — STANDARD
Base SQL existante avec colonnes framework déjà ajoutées manuellement, analyse WinDev propre souhaitée
Mode 2 — SQL_ONLY
Base SQL tierce (impossibilité d'ajouter des colonnes), ou schéma métier devant rester vierge de toute colonne technique
Mode 3 — JOIN
Volume d'INSERT massif (import, batch), performances INSERT critiques
Mode 1 ou 2
Évolutions fréquentes du schéma framework attendues (ajout de colonnes)
Mode 3 — JOIN
ℹ️ Configuration du mode

Le mode est positionné une seule fois au démarrage de l'application, avant tout appel ORM, via la procédure de configuration ORM_Setup. Les trois valeurs possibles sont les constantes suivantes :

METADATA_MODE_STANDARD = 1 METADATA_MODE_SQL_ONLY = 2 METADATA_MODE_JOIN = 3