SQL local (FireDAC)

De RAD Studio
Aller à : navigation, rechercher

Remonter à Utilisation des commandes (FireDAC)

Informations générales

La fonctionnalité SQL local autorise l'exécution de commandes SQL, où les descendants de TDataSet sont utilisés à la place des tables de base de données. Elle est basée sur la base de données SQLite et supporte une grande partie du dialecte SQL de SQLite. Comme nom de table, elle utilise le nom d'un TDataSet (valeur de la propriété Name) ou un nom spécifié. Chaque ensemble de données interrogeable doit être enregistré avec TFDLocalSQL, le moteur SQL local.

Toutes les opérations de lecture et d'écriture sont effectuées via l'API de TDataSet avec des extensions. Le moteur supporte aussi bien des ensembles de données FireDAC ou autres. La fonctionnalité SQL local est plus efficace avec des ensembles de données FireDAC. Eventuellement, pour les ensembles de données non FireDAC, l'interface IFDPhysLocalQueryAdapter peut être implémentée en tant que classe adaptateur et recensée avec le moteur SQL local.

Les applications possibles de SQL local sont les suivantes :

  • Requêtes hétérogènes (les ensembles de données interrogeables comportent des ensembles de résultats de différentes bases de données).
  • Base de données en mémoire (les TFDMemTable servent d'ensembles de données).
  • Mode hors ligne avancé. Dans ce cas, même si la base de données principale n'est pas accessible, une application peut toujours effectuer les requêtes SQL.
  • Client DataSnap avancé (les données fournies par le pilote DataSnap au client peuvent être interrogées localement).
  • Migration simplifiée. Un développeur peut utiliser des objets TDataSet tiers dans une application, et utiliser l'API de FireDAC pour travailler avec ces sources de données.

Configuration

FireDAC utilise le pilote SQLite comme moteur SQL local. L'application doit donc en premier lieu disposer d'une connexion "locale" SQLite. Il peut s'agir d'une connexion permettant l'accès en lecture-écriture basée sur un fichier, par exemple une connexion en mémoire. Nous recommandons l'utilisation d'une connexion en mémoire. Pour la configurer, exécutez les étapes suivantes :

L'application doit connecter les ensembles de données au moteur SQL local. Pour cela, effectuez les opérations suivantes :

  • Déposez un composant TFDLocalSQL sur la fiche.
  • Définissez sa propriété Connection sur un objet de connexion locale SQLite.
  • Vérifiez/assignez une valeur à la propriété Name de l'ensemble de données. Cette étape est nécessaire pour les ensembles de données créés de manière dynamique dans le code.
  • Pour un ensemble de données FireDAC, définissez la propriété TFDAdaptedDataSet.LocalSQL sur l'instance TFDLocalSQL.
  • Ou, pour des ensembles de données FireDAC et autres, utilisez la collection TFDLocalSQL.DataSets pour recenser le TDataSet et l'adaptateur facultatif avec le moteur SQL local. La collection DataSets permet également de spécifier un autre nom d'ensemble de données.

Enfin, activez les objets suivants :

  • Activez la connexion locale SQLite.
  • Activez le moteur SQL local en définissant TFDLocalSQL.Active sur True.
Remarque : Si l'application utilise des ensembles de données de base et des ensembles de données locaux connectés à la même connexion SQLite, la connexion doit être activée explicitement avant qu'un ensemble de données de cette connexion soit ouvert/exécuté/préparé. Sinon, une exception est déclenchée.

Il est également possible de soumettre les ensembles de données au moteur SQL local en utilisant le gestionnaire d'événement TFDLocalSQL.OnGetDataSet.

Tous les ensembles de données associés sont alors recensés par le moteur lorsque la connexion locale et le moteur SQL local sont tous deux actifs. L'association d'un nouvel ensemble de données ne requiert aucune réouverture, celui-ci étant recensé automatiquement. Après le recensement, l'ensemble de données est ouvert. La structure d'un TFDMemTable doit être définie avant son ouverture. Lorsque l'application procède au recensement massif d'ensembles de données, nous recommandons de désactiver le moteur SQL local, puis de le réactiver à la fin de la tâche.

L'application peut définir TFDLocalSQL.SchemaName sur un préfixe de schéma, qui sera utilisé dans les requêtes SQL. L'application peut utiliser plusieurs TFDLocalSQL connectés à la même connexion avec ou sans nom de schéma spécifié. Mais chaque TFDLocalSQL.SchemaName d'une connexion SQLite doit être unique. Un nom de schéma permet d'organiser les ensembles de données en groupes logiques. Lorsqu'un nom de schéma est spécifié, l'ensemble de données figurant dans une commande SQL peut être référencé en tant que <ensemble de données> ou <schéma>.<ensemble de données>.

L'application peut éventuellement définir TFDLocalSQL.MultipleCursors sur False pour éviter le clonage/la copie d'un ensemble de données. SQLite crée un curseur pour exécuter une commande SQL faisant référence à un ensemble de données. L'API de TDataSet ne peut conserver qu'une seule position. Pour remédier à cela, FireDAC clone un ensemble de données FireDAC en utilisant un TFDMemTable ou copie un ensemble de données non FireDAC dans un TFDMemTable. Lorsque le programmeur est certain qu'un ensemble de données sera utilisé uniquement une fois par seconde, il peut définir MultipleCursors sur False pour améliorer la performance. Nous ne recommandons pas de définir MultipleCursors sur False dans le cas des ensembles de données unidirectionnels.

Interrogation

Pour effectuer une requête SQL locale, l'application doit utiliser un TFDQuery/TFDCommand, et définir Connection/ConnectionName sur la connexion locale SQLite, également définie pour TFDLocalSQL.Connection. L'application peut alors exécuter des requêtes SQL comme elle le ferait avec des connexions SQL non locales.

Pendant le traitement de la requête, un ensemble de données interrogeable est désactivé par DisableControls, puis réactivé à la fin du traitement. Pour qu'un ensemble de données reste activé, définissez TFDLocalSQL.DisableControls sur False. Avant la lecture d'un ensemble de données, le gestionnaire d'événement TFDLocalSQL.OnOpenDataSet est appelé.

Le moteur SQL local supporte le dialecte SQL de SQLite avec certaines limitations. Les commandes SQL suivantes ne sont pas supportées pour les sources de données TDataSet :

  • ALTER TABLE ... ADD COLUMN. Modifiez plutôt la structure de l'ensemble de données.
  • DROP TABLE. Lorsqu'un ensemble de données est retiré du moteur SQL local, il est automatiquement supprimé (et non pas libéré).
  • CREATE INDEX / DROP INDEX. Au lieu des index SQL, utilisez les index de l'ensemble de données.
  • CREATE TRIGGER / DROP TRIGGER. Au lieu des déclencheurs, utilisez les événements de l'ensemble de données.

Le moteur SQL local ne supporte pas les ensembles de données avec plusieurs ensembles de résultats.

Le moteur SQL local supporte les commandes SQL INSERT/UPDATE/DELETE en tant que transactions et points de sauvegarde. Il transforme également les commandes SQL correspondantes en appels à l'API de TDataSet.

Le moteur SQL local supporte INSERT ou REPLACE, mais utilise uniquement les champs de clé primaire pour trouver un enregistrement à remplacer, en cas de violation d'une contrainte de clé primaire ou unique. Par ailleurs, lorsque seuls quelques champs sont spécifiés dans INSERT INTO ou REPLACE INTO (<liste de champs>), les champs qui ne sont pas spécifiés obtiennent des valeurs NULL au moment de la mise à jour.

Compatibilité

Le moteur SQL local utilise l'API de TDataSet avec des extensions fournies par l'interface IFDPhysLocalQueryAdapter. Les ensembles de données FireDAC implémentent cette interface. Eventuellement, pour les ensembles de données non FireDAC, un développeur peut créer une classe implémentant l'interface, et assigner son instance à la propriété TFDLocalSQL.DataSets[..].Adapter.

Par ailleurs, pour effectuer des opérations SQL locales, un ensemble de données doit être conforme aux exigences suivantes :

Opération Exigences
INSERT Obligatoirement :
  • La méthode Append.
  • La méthode Post.

Facultativement :

  • PSGetKeyFields doit retourner des champs de clé primaire.
UPDATE Obligatoirement :
  • La méthode Edit.
  • La méthode Post.
  • La méthode Locate.

Facultativement :

  • PSGetKeyFields doit retourner des champs de clé primaire.
DELETE Obligatoirement :
  • La méthode Delete.
  • La méthode Locate.

Facultativement :

  • PSGetKeyFields doit retourner des champs de clé primaire.
Tri / ORDER BY Facultativement :
  • Si IFDPhysLocalQueryAdapter.Features contient afIndexFieldNames, la propriété IFDPhysLocalQueryAdapter.IndexFieldNames est utilisée pour trier l'ensemble de données.
Filtre / WHERE Facultativement :
  • Si IFDPhysLocalQueryAdapter.Features contient afRanges, la méthode IFDPhysLocalQueryAdapter.SetRange est utilisée pour filtrer l'ensemble de données.
  • Si IFDPhysLocalQueryAdapter.Features contient afFilters, la propriété Filter est également utilisée.
Points de sauvegarde Obligatoirement :
  • Si IFDPhysLocalQueryAdapter.Features contient afCachedUpdates, afSavePoint, la propriété IFDPhysLocalQueryAdapter.Savepoint est utilisée.
Transactions Obligatoirement :
  • La méthode PSStartTransaction.
  • La méthode PSEndTransaction.


Exemple 1

Voici une requête hétérogène utilisant des tables SQL Anywhere et Oracle et des TFDQuery FireDAC :

// setup connection and query to "Orders" table in SQL Anywhere DB
FDConnection1.ConnectionDefName := 'ASA_Demo';
FDConnection1.Connected := True;
FDQuery1.Connection := FDConnection1;
FDQuery1.SQL.Text := 'select * from Orders';
// link dataset to Local SQL engine
FDQuery1.LocalSQL := FDLocalSQL1;

// setup connection and query to "Order Details" table in Oracle DB
FDConnection2.ConnectionDefName := 'Oracle_Demo';
FDConnection2.Connected := True;
FDQuery2.Connection := FDConnection2;
FDQuery2.SQL.Text := 'select * from "Order Details"';
// link dataset to Local SQL engine
FDQuery2.LocalSQL := FDLocalSQL1;

// setup SQLite in-memory connection
FDConnection3.DriverName := 'SQLite';
FDConnection3.Connected := True;
// link Local SQL to SQLite connection
FDLocalSQL1.Connection := FDConnection3;
FDLocalSQL1.Active := True;

// execute SELECT query on above datasets
FDQuery3.Connection := FDConnection3;
FDQuery3.SQL.Text := 'SELECT * FROM FDQuery1 LEFT JOIN FDQuery2 ON FDQuery1.OrderID = FDQuery2.OrderID';
FDQuery3.Active := True;


Exemple 2

Voici une requête hétérogène utilisant des TADOQuery ADO et des TFDQuery FireDAC :

// setup connection and query to "Orders" table
ADOQuery1.SQL.Text := 'select * from Orders';
// link dataset to Local SQL engine
with FDLocalSQL1.DataSets.Add do begin
  DataSet := ADOQuery1;
  Name := 'Orders';
end;

// setup connection and query to "Order Details" table
ADOQuery2.SQL.Text := 'select * from "Order Details"';
// link dataset to Local SQL engine
with FDLocalSQL1.DataSets.Add do begin
  DataSet := ADOQuery2;
  Name := 'Order Details';
end;

// setup SQLite in-memory connection
FDConnection1.DriverName := 'SQLite';
FDConnection1.Connected := True;
// link Local SQL to SQLite connection
FDLocalSQL1.Connection := FDConnection1;
FDLocalSQL1.Active := True;

// execute SELECT query on above datasets
FDQuery1.Connection := FDConnection1;
FDQuery1.SQL.Text := 'SELECT * FROM Orders o LEFT JOIN "Order Details" od ON o.OrderID = od.OrderID';
FDQuery1.Active := True;

Voir aussi

Exemples