Fragen zu TFDQuery, TFDStoredProc und TFDUpdateSQL

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu FAQ (FireDAC)

Dieses Thema enthält eine Liste mit Fragen und Antworten zu TFDQuery, TFDStoredProc und TFDUpdateSQL.

F1: Kann ich TFDQuery verwenden, es mit einem Datenmengen-Provider verbinden und die Daten in eine Embarcadero-Client-Datenmenge abrufen?

A: TFDQuery besteht aus TFDMemTable, TFDTableAdapter und mehreren TFDCommands. Daher verfügt TFDQuery über alles, was zum Ausführen von SQL-Anweisungen, Senden von Parameterdaten, Empfangen und Speichern von Ergebnismengen, Durchsuchen von Ergebnismengen und Eintragen von Änderungen in eine Datenbank erforderlich ist. Es gibt keinen Grund, warum Sie TFDQuery und einen Datenmengen-Provider und eine Client-Datenmenge verwenden sollten.

Sie können anstelle von TFDQuery die Komponenten TFDMemTable, TFDTableAdapter und TFDCommand direkt verwenden. Dadurch erzielen Sie eine größer Flexibilität, es ist aber auch ein höherer Programmieraufwand erforderlich. Denken Sie zum Beispiel an synchronisierte zwischengespeicherte Aktualisierungen für Datenmengen.

Kurz gesagt, TFDQuery stellt eine optimale "Verkürzung" der täglichen Anwendungsprogrammierung dar.

F2: Wie kann ich FDStoredProc dazu bringen, manuell angegebene Parameter zu verwenden?

A: Schließen Sie fiMeta aus FetchOptions.Items aus.

Wenn Sie Parameter manuell erstellen, müssen Sie fiMeta aus FetchOptions.Items ausschließen. Wenn es angegeben ist, ruft FireDAC die Parameterdefinitionen für gespeicherte Prozeduren aus einer Datenbank ab und füllt die Params-Sammlung neu.

Wenn Sie Schwierigkeiten mit der manuellen Definition von Parametern haben, füllen Sie die Params-Sammlung automatisch und prüfen Sie, wie die Parameter definiert sind. Dann vergleichen Sie die Definitionen mit Ihrem Code.

F3: "[FireDAC][Phys]-308. Anweisung, die keine Ergebnismengen zurückgibt, kann nicht geöffnet/definiert werden" und "[FireDAC][Phys]-310. Anweisung, die Ergebnismengen zurückgibt, kann nicht ausgeführt werden". Was bedeuten diese Exceptions?

A: Die Exception "[FireDAC][Phys]-308. Anweisung, die keine Ergebnismengen zurückgibt, kann nicht geöffnet/definiert werden" wird ausgelöst, wenn die Anwendung die Open-Methode für eine SQL-Anweisung ausführt, die keine Ergebnismenge zurückgibt. Die Exception wird nach Ausführung der SQL-Anweisung ausgelöst, aber das DBMS hat keine Ergebnismengen zurückgegeben.

Die Exception "[FireDAC][Phys]-310. Anweisung, die Ergebnismengen zurückgibt, kann nicht ausgeführt werden" wird ausgelöst, wenn die Anwendung die ExecSQL-Methode für eine SQL-Anweisung ausführt, die eine Ergebnismenge zurückgibt. Ob die Anweisung eine Ergebnismenge zurückgibt oder nicht, wird vom FireDAC-SQL-Anweisungspräprozessor bestimmt. Wenn die Anweisung als SELECT-Anweisung oder als eine ihrer Formen erkannt wird, dann wird eine Ergebnismenge zurückgegeben, ansonsten nicht.

In manchen Fällen kann FireDAC möglicherweise nicht erkennen, ob eine SQL-Anweisung eine Ergebnismenge zurückgibt oder nicht. Und manchmal müssen Ad-hoc-Anwendungen eine SQL-Anweisung ausführen, unabhängig davon, wie viele Ergebnismengen sie zurückgibt. Was können Sie in diesen Fällen tun? Es gibt zwei grundlegende Lösungen:

1)

 FDQuery1.OpenOrExecute;

Diese Anweisung könnte intern [FireDAC][Phys]-308 auslösen, aber aus OpenOrExecute wird keine Exception weitergegeben, und eine SQL-Anweisung wird tatsächlich ausgeführt. Außerdem gibt die Methode True zurück, wenn die Anwendung eine Ergebnismenge liefert.

2)

 FDQuery1.Command.CommandKind := skInsert;
 FDQuery1.ExecSQL;

Sie müssen FireDAC nur über den Typ der Anweisungen (INSERT oder andere) informieren, die keine Ergebnismengen liefern.

F4: Die Exception "Zu wenig Arbeitsspeicher" wird beim Aufrufen von FDQuery.Execute(FDQuery.Params.ArraySize) ausgelöst. ArraySize beträgt etwa 90.000. Was ist falsch?

A: 1) 90.000 ist für alle DBMS zu groß, weil die Daten mehrmals zwischengespeichert werden (Parameter, DBMS-API-Puffer, Netzwerkpaketpuffer usw.). Außerdem ist wahrscheinlich jeder Datensatz sehr groß. Des Weiteren kann eine Anwendung an DBMS-API-Grenzen stoßen, wie z. B. die Obergrenze für die Array-Größe. Bei Oracle liegt die Obergrenze bei $7FFF. Bei anderen DBMSs ist die Obergrenze von der Netzwerkpaketgröße usw. abhängig.

2) Unterteilen Sie 90.000 in Blöcke mit jeweils 500 - 5000 Elementen. Siehe die Demo "AD03-ArrayDML". Im Allgemeinen sollten Sie ein Array bis zur Blockgröße füllen, dann "Execute" mit der Blockgröße aufrufen, dann erneut füllen, "Execute" aufrufen usw.

Mit Firebird kann ArraySize problemlos auf 1.000.000 (60 Sek.) gesetzt werden.

Es wurde eine empirische Formel gefunden, die es ermöglicht, die maximale Größe eines Arrays zu bestimmen. FireDAC unterteilt ein großes Array automatisch in mehrere Datenblöcke.

Eine ähnliche Formel für Oracle zu finden, ist nicht so einfach. Oracle unterstützt eine Größe bis zu $7FFF, trotzdem treten Zugriffsverletzungs- oder andere Probleme bei großen Arrays auf.

Jedenfalls kann vor dem Aufruf von "Execute" zu wenig Arbeitsspeicher vorhanden sein, wenn die Datensätze zu groß sind.

F5: Wie kann ich ermitteln, ob alle FDQuery-Datensätze abgerufen wurden?

A: Überprüfen Sie die Eigenschaft SourceEOF.

F6: Ich möchte einen Datensatz (über reines SQL) einfügen und IDENTITY/SEQUENCE zurückerhalten. Was ist dafür der effektivste, für mehrere Datenbanken geeignete Weg?

A: 1) TFDConnection verfügt über die Methode GetLastAutoGenValue. Abhängig vom DBMS gibt diese Methode den in einer Sitzung zuletzt generierten Wert zurück. Für Oracle wäre dies beispielsweise:

 SELECT <AName>.CURRVAL FROM dual

Bei MySQL wird auf die MYSQL-API zugegriffen, um den Wert ohne eine SQL-Abfrage zu ermitteln. Wenn ein DBMS keine Sequenzen/Generatoren unterstützt, dann wird der Parameter AName einfach ignoriert.

2) Es gibt keine Möglichkeit, einen SQL-Befehl für mehrere Datenbanksysteme zu schreiben, der einen Datensatz einfügt und einen automatisch generierten Wert zurückgibt. Für Oracle wäre dies beispielsweise:

 INSERT ... INTO ... RETURNING ID INTO :ID

Für PostgreSQL sind dafür zwei separate Anweisungen erforderlich:

 INSERT ... INTO ..
 SELECT CURRVAL(...)

Wenn Sie mit den Methoden "TDataSet Insert/Post" eine Einfügung in einer Datenbank vornehmen, generiert FireDAC je nach Art des DBMS geeignete effiziente SQL-Anweisungen.

F7: Wie kann ich die Transaktion zurücksetzen, nach dem der Benutzer die Abfrageausführung im Modus "amCancelDialog" abgebrochen hat?

A: Dafür gibt es zwei Möglichkeiten:

1)

 FDTransaction1.StartTransaction;
 try
   FDQuery1.ExecSQL;
   FDTransaction1.Commit;
 except
   on E: EAbort do
     // user canceled the command execution
     ADTransaction1.Rollback;
 end;

2) Festlegen der Ereignisbehandlungsroutine TFDQuery.OnError. Wird die Ausführung einer Anweisung abgebrochen, wird diese Ereignisbehandlungsroutine aufgerufen, und der Parameter AException erfüllt die Bedingung:

 EFDDBEngineException(AException).Kind = ekCmdAborted;

F8: Meine Abfrage, die die Zeichen "&", "!" enthält, wird nicht korrekt ausgeführt. Was ist falsch?

A: Zum Beispiel schlägt die folgende Abfrage mit Standardoptionen fehl:

 FDQuery1.SQL.Text := 'select * from xy where Fieldname = ''xxx&n''';
 FDQuery1.open;

In der SQL-Anweisung, die ein DBMS erhält, fehlt "&n". Und zwar, weil "&" den Anfang einer Makrovariable angibt. Standardmäßig hat jede Variable einen leeren Wert. Daher wird "&n" durch einen leeren String ersetzt. Setzen Sie ResourceOptions.MacroCreate und MacroExpand auf False, wenn Sie keine Makros verwenden.

F9: Ich erhalte beim Zugreifen auf die Parameter einer gespeicherten Prozedur den Fehler "Parameter Xxx nicht gefunden". Was ist falsch?

A: Sehen Sie sich den folgenden Code an:

 FDStoredProc1.StoredProcName := 'TestProc';
 FDStoredProc1.Prepare;
 FDStoredProc1.ParamByName('Par').AsInteger := 100;

Dafür kann es verschiedene Gründe geben:

  • In der Datenbank ist die gespeicherte Prozedur "TestProc" nicht vorhanden und muss erstellt werden.
  • Abhängig vom DBMS kann sich "TestProc" in einem ungültigen Status befinden und muss validiert werden.
  • Abhängig vom DBMS liegt der Name der gespeicherten Prozedur in einer gemischten Schreibweise (groß/klein) vor und muss in Anführungszeichen gesetzt werden.
  • Wenn fiMeta aus FetchOptions.Items ausgeschlossen ist, muss es eingeschlossen oder manuell erstellt werden.
  • Die gespeicherte Prozedur hat keinen Par-Parameter; der Parametername muss korrigiert oder Par hinzugefügt werden.
  • Abhängig vom DBMS kann dem Parameternamen "@" vorangestellt oder ResourceOptions.UnifyParams auf True gesetzt werden.