Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi DB Abfrage als JSON ausgeben (https://www.delphipraxis.net/214733-db-abfrage-als-json-ausgeben.html)

Whookie 29. Feb 2024 16:26

Datenbank: dbExpress • Version: ? • Zugriff über: sqlite

DB Abfrage als JSON ausgeben
 
Hallo zusammen,
ich habe aktuell eine sqlite-DB mit der ich über dbExpress zugreife die DB enthält unter anderem zwei TEXT Felder im Format '[1,2,3,4,5...300]' mit 80 bis 2000 Werten. Diese Felder (und andere) hole ich mir über eine entsprechende TSQLQuery und wandle das ganze nach JSON (vereinfacht):

Delphi-Quellcode:
    LQueryObject := TJSONObject.Create;
    LQArray := TJSONArray.Create;
    LQueryObject.AddPair('data', LQArray);
    fQuery.CommandText := '.....';

    fQuery.Open;
    fQuery.First;
    while Not fQuery.Eof do
    begin
      LItem := TJSONObject.Create;
      for i := 0 to fLongVSQuery.Fields.Count-1 do
      begin
        if Not fQuery.Fields[i].IsNull then
        begin        
          LItem.AddPair(
            fQuery.FieldDefs[i].Name,
            fQuery.Fields[i].AsString
          )
        end;
      end;

      LQArray.AddElement(LItem);
      fQuery.Next;
    end;
    fQuery.Close;

    Result := LQueryObject.ToString;
    ...

Alle "anderen" Felder meiner Abfrage sind Strings und können wie oben übernommen werden. Für die TEXT Felder funktioniert das nicht, denn ich bekomme (natürlich) als Ergebnis:

Code:
{
  "data": [
    {
      "...": "...."
      "myarray": "[1,2,3,4,5..,300]"      statt: "myarray": [1,2,3,4,5,..,300]
    {
      ...
    }
  ]
}
Daher habe ich für diese Felder eine "Sonderbehandlung" implementiert:

Delphi-Quellcode:
  LItem.AddPair(
    fQuery.fFieldDefs[i].Name,
    TJSONObject.ParseJSONValue(fQuery.Fields[i].AsString) As TJSONArray;
  )

Das ergibt zwar sauberen JSON-Output, ist aber leider extrem spürbar bei der Abfragedauer (bei ~ 1000 zurückgegebenen Objekten).

Daher die alles entscheidende Frage:

Ist es irgendwie möglich, den schon vorhandenen String zu verwenden ohne ihn zuerst zurück in ein TJSON-Integer-Array und dann wieder in einen String zu wandeln?

Ich habe das ganz auch mit einer TStringList umgesetzt (also JSON selber erzeugen), dass ist viel schneller aber auch deutlich weniger schön/flexibel, ist das eine vernünftige Lösung?

Neumann 1. Mär 2024 10:53

AW: DB Abfrage als JSON ausgeben
 
Was ist wenn man die strings einfach quoted "1,2,..300"

Uwe Raabe 1. Mär 2024 11:58

AW: DB Abfrage als JSON ausgeben
 
Zitat:

Zitat von Neumann (Beitrag 1534025)
Was ist wenn man die strings einfach quoted "1,2,..300"

Das Problem ist hier der Aufruf von AddPair, dessen zweiter Parameter eben ein String ist (wegen AsString), wo es doch eigentlich ein Array sein sollte. Die Umwandlung dieses Strings mittels ParseJSONValue erfüllt ja auch ihren Zweck - ist halt nur spürbar langsamer. Immerhin werden da eine ziemliche Anzahl von JsonValues erzeugt, die am Ende ja wieder in den JSON-Ergebnisstring umgewandelt werden.

Ein Ausweg wäre ein manuelles Schreiben des JSON-Strings.

himitsu 1. Mär 2024 12:02

AW: DB Abfrage als JSON ausgeben
 
Jupp, AsString ist nunmal ein String, also wird es als String gespeichert.
Du mußt das also zerlegen und dann daraus ein JSON-Array machen.

Du kannst manuell diese Integer-Liste zerlegen und ein JsonArray bauen, oder (mit den [ ] drumrum) es vom JsonParser in ein Array konvertieren lassen
und das Array dann einfügen.


Wenn/da die JSON-Implementation vom Delphi jetzt nicht sooo flott ist,
bleibt nur der Ausweg unschön den JSON-Text selbst zusammenzubauen
oder eine andere JSON-Lib zu suchen.

Whookie 1. Mär 2024 13:55

AW: DB Abfrage als JSON ausgeben
 
Danke für die Hinweise! Beim Überlegen bin ich dann auf folgende Möglichkeit gekommen:

Delphi-Quellcode:
type
  TJSONStringedArray = class(TJSONString)
  public
    procedure ToChars(Builder: TStringBuilder); override;
  end;

implementation

{ TJSONStringArray }

procedure TJSONStringedArray.ToChars(Builder: TStringBuilder);
begin
//  inherited;
  if Not IsNULL then
  begin
    Builder.Append(Value);
  end;
end;
Hinzufügen, kann ich mein Array dann wie folgt:

Delphi-Quellcode:
  ...
    LItem.AddPair(
      AQuery.fJSONDefs[i].Name,
      TJSONStringedArray.Create(fQuery.Fields[i].AsString)
    )
Damit stimmt dann auch die Ausgabe im JSON.

Anm.: Man könnte noch ToBytes() überschreiben um die Ausgabe in einen Stream zu ermöglichen (verwende ich aber nicht).


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:39 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz