Parameter.AsString fehlgeschlagen unter Oracle / MSSQL - Parameter.Value 2-Byte-Zeichen unter Oracle

8

Nach dem Wechsel zu FireDAC habe ich Probleme, diesen Code für MSSQL / Oracle zu verwenden:

%Vor%

AKey und S sind beide Strings.

Die Open-Anweisung gibt einen Fehler

%Vor%

beim Verbinden mit einer MSSQL- oder Oracle-Datenbank; nicht beim Verbinden mit FireBird.
Nach dem FetchParams ist DataFormsettings.params[1].datatype immer ein ftString .

Wenn ich

ersetze %Vor%

mit

%Vor%

... die Open-Anweisung enthält keine Fehler. Ich dachte, das hätte es gelöst, obwohl ich den Fehler nicht wirklich verstanden habe. Nach allem sollten dies alle Delphi-String-Typen sein ...
Aber jetzt scheitert die Zuweisung für Oracle (nicht FireBird oder MSSQL) in dem Sinne, dass ich 2-Byte-Zeichen zurückgegeben bekomme. S enthält:

%Vor%

Ich kann das z. B. mit

umgehen %Vor%

für Oracle, aber (natürlich) wenn Sie die anderen zwei Datenbanktypen verwenden, die nicht funktionieren:

%Vor%

Was fehlt mir hier? Insbesondere möchte ich nur die AsString-Retrieval / Zuweisungen zum Arbeiten bekommen.
Beachten Sie, dass Wenn Sie die AsString-Eigenschaft festlegen, wird die DataType-Eigenschaft im FireDAC TFDParam.AsString Dokumentation . Es scheint, als ob die Parameter-Wertzuweisung nur den Typ von ftString auf ftWideString umschaltet (wie durch den ursprünglichen Fehler angezeigt).

DataFormSettings ist ein TClientDataSet in einer Clientanwendung, die mit einer Serveranwendung verbunden ist, in der sich TDataSetProvider und TFDQuery befinden. Die Abfrage ist

%Vor%

Die Tabellen wurden wie folgt erstellt:

Feuervogel:

%Vor%

Oracle:

%Vor%

MSSQL:

%Vor%

Ich habe überprüft, dass TT_VIEWDATA korrekte Daten in allen Datenbanken enthält; Es ist eine lange Zeichenfolge, die CRLFs enthält:

%Vor%

Anmerkungen:

  • Gegenwärtig auf SQL Server 2008 und Oracle 10 getestet, aber ich erwarte, dass dies für andere Versionen nicht anders ist.
  • FWIW, select * from NLS_database_PARAMETERS where parameter like '%CHARACTERSET%' gibt NLS_CHARACTERSET=WE8MSWIN1252 und NLS_NCHAR_CHARACTERSET=AL16UTF16
    zurück Die Abfrage SELECT dump(dbms_lob.substr(tt_viewdata,100,1), 1016), tt_viewdata FROM tt_formsettings bestätigt, dass der CLOB ASCII-Bytes für die Codepage Win1252 enthält:
    Typ=1 Len=100 CharacterSet=WE8MSWIN1252: 5c,53,6f,66,74,77,61,72,65,5c,54,69,6d,65,54,65,6c,6c,5c,44,65,...
  • FieldByName().AsANSIString liefert die gleichen Ergebnisse wie FieldByName().AsString

Weitere Informationen: Dies ist eine Legacy-Anwendung mit persistenten Felddefinitionen für DataFormsettings TClientDataset . TT_VIEWDATA ist definiert als TMemoField :

%Vor%

In einer kleinen Testapp (direkt verbunden mit Oracle; nicht Client-Server) ließ ich Delphi die Felddefinitionen hinzufügen und sagte dann:

%Vor%

Wenn ich das in der Haupt-App verwende, funktioniert Oracle gut, aber dann bekomme ich 'Müll' für MSSQL.

Ich experimentierte auch mit dem Einrichten von Zuordnungsregeln für die Oracle-Verbindung wie (viele Variationen):

%Vor%

aber das hat nicht geholfen.

    
Jan Doggen 06.12.2017, 11:17
quelle

2 Antworten

5

Hier ist der Grund, warum es nicht funktioniert:

In FireDAC.Stan.Option :

%Vor%

In der Tat können Probleme sein .

Die Lösung besteht darin, eine Zuordnungsregel hinzuzufügen, die dtWideHMemo in dtMemo konvertiert.
Danach funktioniert das Lesen und Schreiben in den CLOB .AsString einwandfrei.

Wird als RSP-19600 im Embarcadero Quality Portal gemeldet.

Der Vollständigkeit halber: Da das in meiner anderen Antwort erwähnte Mapping nicht mehr aktiv ist, müssen Sie den Zugriff auf die Parameter mit .Value anstelle von .AsString.

ändern     
Jan Doggen 20.12.2017, 11:28
quelle
1

Dies ist keine definitive Lösung, siehe die letzten Anmerkungen vor den Codeblöcken. Es fühlt sich immer noch an wie ein Hack. Ich füge es der Frage nicht hinzu (als 'Versuche'), weil das letztendlich funktionieren würde.

Es gab zwei Dinge, und sie können beide mit den folgenden Änderungen umgehen:

  1. Der Param-Typ wurde geändert Fehler in der Bewertung von Params
  2. Felddefinitionen und das FieldByName().AsString retrieval / assigning funktioniert nicht

Beachten Sie, dass ich durch Design-Time-Felddefinitionen in der gesamten Anwendung eingeschränkt bin, die alle drei Datenbanktypen verarbeiten müssen, insbesondere das DataFormSettingsTT_VIEWDATA persistent-Feld ist ein TMemoField .

Wenn Sie bei den am Ende der Frage genannten Tabellendefinitionen eine TFDConnection -> TFDQuery -> TDataSetProvider -> TClientDataSet einrichten und die Felddefinitionen mit Alle Felder hinzufügen hinzufügen, hat DataFormSettingsTT_VIEWDATA den Typ:

  • TMemoField mit BlobType=ftMemoField für FireBird

  • TMemoField mit BlobType=ftWideMemoField für MSSQL

  • TWideMemoField mit BlobType=ftWideMemoField für Oracle.

Manuelles Editieren von .DFM und .PAS, um das TWideMemoField von% zurück auf TMemoField zu setzen (nun, ich muss es nicht ändern, es ist Legacy-Code), wenn ich auch:

  • force BlobType=ftWideMemoField für die Entwurfszeit TMemoField s zur Laufzeit (Ich kann das in OnCreate in einem Elternteil tun, von dem alle meine Datenmodule abstammen);

  • behandelt den String-Abruf nur für Oracle als TEncoding.Unicode.GetString(FieldByName(SFormSettingsViewData).AsBytes) .

Aber das ist immer noch nicht optimal. Mein Clientcode mit dem TClientDataSet muss nun wissen, um welche Art von Datenbank es sich handelt . Ich habe Mittel in der Client-App, um den Server dafür abzufragen.

Hier ist eine Beispiel-App mit diesen Änderungen:

uFireDacOracleBlob.pas datei:

%Vor%

uFireDacOracleBlob.dfm datei:

%Vor%

Hinweis: Die Tatsache, dass die Parameterzuweisung jetzt (auch) funktioniert, ist in der Datentypzuordnung ( FireDAC) Dokumentation:

  

Im Falle einer Ergebnismengenspalte definiert jede Regel eine Transformation eines Quelldatentyps, der von einem Treiber zurückgegeben wird, in einen Zieldatentyp, der von einer Anwendung bevorzugt wird. Im Falle eines Befehlsparameters definiert die Regel eine Umwandlung eines Zieldatentyps, der von einer Anwendung spezifiziert wird, in einen Quelldatentyp, der von einem Treiber unterstützt wird. Alle Regeln, mit Ausnahme der namensbasierten, funktionieren in beiden Fällen bidirektional.

    
Jan Doggen 11.12.2017 09:55
quelle