Curseurs SQL (tech)

De Wiki1000

Sommaire

Introduction

Les requêtes SQL (TQuery) permettent d'accéder à une ou plusieurs tables d'une base de données en utilisant des instructions SQL.

A la différence des curseurs, les requêtes SQL ne s’appuient pas sur le modèle objet mais sur le modèle relationnel sous-jacent.

Elles ne doivent donc être utilisées que dans les cas où les fonctionnalités orientées objets disponibles s’avèrent insuffisantes.

Généralement l’utilisation d’une requête SQL suit le schéma suivant :

  1. L’objet requête est créé avec la fonction QueryBroker.
  2. Le code SQL est défini.
  3. La requête est ouverte.
  4. Tant qu’il existe des données dans le résultat la requête est « fetchée » ; les données sont retournées ligne par ligne dans cette boucle.
  5. La requête est fermée.

Bien que l’écriture du code SQL soit libre, le développeur doit respecter un certain nombre de règles pour garantir que ce code soit portable d’un serveur à l’autre.

Tip-20px.png Tip : L'utilisation des requêtes SQL doit être évitée.

Déclaration d'une variable requête SQL

Les requêtes SQL doivent être déclarées :

var q:TQuery;

Création d'une requête SQL

Une requête est créée avec la fonction globale QueryBroker.

function QueryBroker(const iDatabaseURL,iTraceName,iClasseName:string):TQuery;
iDatabaseURL string URL de la base de données. Si ce paramètre est vide la base de données par défaut est utilisée.
iTraceName string Identifiant de la requête dans la trace.
iClasseName string Nom de la classe métier concernée.

Si cette classe est fournie le résultat de la requête peut être mappé sur un objet métier de la classe indiquée, la propriété Instance est alors utilisable. La requête peut alors être utilisée comme un curseur.

Création d'une requête SQL ODBC

Une requête SQL ODBC utilise le pilote ODBC inclu dans le framework 1000 et peut être exécutée sur une source ODBC quelconque.

function ODBCQueryBroker(const iODBC_DSN:string; const iTraceName:string):TQuery;
iODBC_DSN string Chaîne d'identification ODBC de connexion
iTraceName string Identifiant de la requête dans la trace.

Propriétés

Propriétés de paramétrage de la requête

ACLASSNAME string Nom de la classe métier sur laquelle est mappé la requête.
UPDATEQUERY Boolean Indique si cette requête est une requête de mise à jour.

Si cette propriété est positionnée une requête de mise à jour sera utilisé; sinon une requête de lecture sera utilisée.

Info-20px.png Note : Certains pilotes ne gèrent pas de la même façon les requêtes de mises à jour et les requêtes de lecture.
SQL TStrings Ordre SQL de la requête
TRANSLATOR Translateur SQL Objet technique permettant de formatter le code SQL en fonction du pilote de base de données

Propriétés à l'exécution

la requête====
INSTANCE Objet métier Instance en cours, n'est utilisable que si un nom de classe métier a été utilisée lors de l'appel à QueryBroker et que tous les attribut de la classe ont été retournés par la requête.
EOF Boolean Testez Eof pour déterminer si le curseur est positionné sur le dernier enregistrement d'un ensemble de données.
FIELDCOUNT Integer Consultez la propriété FieldCount pour déterminer le nombre de champs associés à l'ensemble de données.
FIELDS [ INDEX ] TField Utilisez Fields pour accéder aux composants champs en mode indexé.

Méthodes

OPEN
procedure Open;
Ouvre l'ensemble de données.
OPENNE
procedure OpenNE;
Ouvre l’ensemble de données sans provoquer d’exception en cas d’erreur.
FIRST
procedure First;
Appelez First pour placer le curseur sur le premier enregistrement de l'ensemble de données.
NEXT
procedure Next;
Appelez Next pour placer le curseur sur l'enregistrement suivant de l'ensemble de données.
CLOSE
procedure Close;
Ferme un ensemble de données.
CANCEL
procedure Cancel;
Termine la requête en interrompant l’exécution sur le serveur.
CLEAR
procedure Clear;
Réinitialise le contenu SQL de la requête.
EXECSQL
procedure ExecSQL;
La méthode ExecSQL exécute l'instruction SQL affectée à la propriété SQL. ExecSQL est également utilisée pour exécuter les requêtes ne renvoyant pas de curseur aux données (telles que INSERT, UPDATE, DELETE).
Tip-20px.png Tip : Pour les instructions SELECT, utilisez Open à la place de la méthode ExecSQL.
FIELDBYNAME
function FieldByName (const iFieldName : string):TField;
Appelez FieldByName pour obtenir les informations sur un champ lorsque vous en connaissez le nom. FieldName indique le nom d'un champ existant. FieldByName renvoie le composant TField du champ spécifié.
NEXTRESULTSET
procedure NextResultSet;
Passe à l'ensemble résultat suivant dans le cas d'une requête multi-résultat.

L'objet TFIELD représente un champ d'un ensemble de données. Il dispose des propriétés suivantes :

FIELDNAME string Indique le nom de la colonne physique de l'ensemble de données.
NAME string Contient le nom du composant.
ASVARIANT Variant Représente la valeur du champ en type variant.
FIELDNO Integer Indique le numéro d'ordre de la colonne reliée au composant champ dans la table physique sous-jacente à un ensemble de données.
DATATYPE Enum Identifie le type de données du composant champ.
DATALEN Integer
SIZE Integer Indique la taille utilisée dans la définition du champ de la base de données physique pour les types de données gérant différentes tailles.

Exemples

Utilisation de requête pour réaliser des mises à jour

Les requêtes SQL peuvent être utilisées pour réaliser des mises à jour ensemblistes qui ne seraient pas performante si elles étaient réalisées en technologie objet.

Dans ce scénario il faut faire attention à :

  • Les requêtes SQL ne sont pas objets, elles ne peuvent pas être combinées avec une transaction objet.
  • Les requêtes SQL peuvent être incluses à l'intérieur d'une transaction longue; en effet une transaction longue démarre une transaction SQL sur son BeginLongTran et la termine sur son CommitLongTran, les ordres SQL exécutés à l'intérieur sont donc soumis à la transaction.
  • Si aucune transaction explicite n'est démarée la base de données est en mode AUTOCOMMIT, les ordres sont donc validés un par un et ne sont pas transactionnels.

Dans cette exemple le corps de l'exécution démarre une transaction longue et appel une série de mise à jour à l'intérieur de la transaction :

//Procedure doBigUpdate;
begin
  ClassManager.BeginLongTran(1,'TTiers');
  try
    _majService;
    _majContactEtablissement;
    _majSiteUnique;
    ...
    ClassManager.CommitLongTran;
  except
    ClassManager.RollBackLongTran;
    raise;
  end;
end;

Notez que dans cette utilisation d'une transaction longue BatchLongTran est inutile car il ni a pas d'objet métiers participant à la transaction à moins que vous combiniez usage de requête SQL et mise à jour d'objets métiers.

Les procédures de mise à jour s'écrivent ainsi :

//Procedure _majService;
var
  vCursorUpdate: TQuery;
  vSQL : String;
  vTService : String;
  vTSocieteOperateur : String;
begin
  ProgressMessage(_TP('Mise à jour du service'));
 
  vCursorUpdate := QueryBroker('','TSite','');
 
  vTService := ClassManager.FindClassTableName('TService');
  vTSocieteOperateur := ClassManager.FindClassTableName('TSocieteOperateur');
 
  vSQL := ' UPDATE %s SET oidresponsable =
             ( SELECT oidInterlocuteurSociete FROM %s
               WHERE (oidContactEtablissement = %s.oidresponsable)
             )
            WHERE EXISTS
             (  SELECT * FROM %s
                WHERE (oidContactEtablissement = %s.oidresponsable)
              )';
  vSQL := Format(vSQL,[vTService,
                       vTSocieteOperateur,
                       vTService,
                       vTSocieteOperateur,
                       vTService]);
 
  vCursorUpdate.Sql.Add(vSQL);
  vCursorUpdate.ExecSQL;
  vCursorUpdate.Close;
end;

Utilisation de requête pour retrouver la valeur d'un attribut

Dans cet exemple une requête est utilisée pour retrouvé la valeur en base de données d'un objet chargé en mémoire :

var vSumpDispo:TQuery; vSum:Double;
begin
  //
  // QUERYBROKER permet de recuperer la valeur de la BD au lieu de celle de l'instance
  // en mémoire, nécessaire car on prends en compte les reservations.
  //
  vSumDispo := QueryBroker('','TCAPACITEENTREESTOCK','');
  vSumDispo.SQL.Add('SELECT quantiteSortie qte FROM '+ClassManager.FindClassTableName('TCAPACITEENTREESTOCK'));
  vSumDispo.SQL.Add('WHERE (oid = ' + vSumDispo.Translator.dbOutOid(InstanceOid) + ')');
  vSumDispo.Open;
  vSumDispo.First;
  vSum := vSumDispo.FieldByName('qte').AsVariant;
  vSumDispo.Close;
end;
Info-20px.png Note : Cette utilisation est douteuse.

Code métierDéveloppement DSM

Outils personnels