Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Die Sache mit dem Listenproperty (https://www.delphipraxis.net/191901-die-sache-mit-dem-listenproperty.html)

Delbor 3. Mär 2017 10:55

AW: Die Sache mit dem Listenproperty
 
Hi Sakura

Genaugenommen wird die Anfrage bei jedem lesezugriff auf das Property ausgeführt. Die Alternative wäre, die SQL-Anfrage ausserhalb des Datenmoduls dann da ausführen, wo ich sie brauche. Zum Bleistift in einem PageControl zur Anzeige von Metadaten auf der Mainform. Damit hätte ich dann eine weitere Prozedur in der Mainform, die es allenfalls zu ändern (und erstmal zu finden) gibt. Und wenn ich mehrere Informationen, für deren Beschaffung das Datenmodul zuständig ist, von ausserhalb abfrage, habe ich auch ausserhalb eine entsprechende Anzahl Methoden, die mir diese Infos beschaffen - und sollte sich irgendwas ändern, zum Bleistift an der Datenbank/Tabellenstruktur, darf ich alll diese Methoden ausserhalb des Datenmoduls da ändern, wo ich sie angelegt habe. Das muss nicht zwingend die Mainform sein, das kann eine andere Form oder ein Frame - im schlimmsten Fall pro Prozedure/SQL-Statement - sein. Wenn ich das im alles im Datenmodul habe, muss ichs auch nur da ändern.
Auch wenn ich Methoden von ausserhalb nur aufrufe - wenn sich die Art des Aufrufens ändert (Parameter können sich ändern etc), darf ich alle diese Aufrufe an verschiedenen Stellen des Programmes ändern.

Delphi-Quellcode:
Eine gute Richtlinie ist es aber immer so zu entwickeln, als könnten solche Informationen an mehreren Stellen gleichzeitig gebraucht werden, das macht spätere Erweiterungen leichter. Auch bei Desktopanwendungen ist Multi-Threading schon lange keine Ausnahme mehr.


Ja eben: genau deswegen ist es besser, das Datenmodul stellt die Infos als Propery bereit. Ansonsten müsste jede dieser Stellen das SQL-Statement aufrufen. Das Statement selbst, bzw. desse Ausführung, dürfte vo der Performance her kaum ins Gewicht fallen.
Und nochmals: sollte ich mit einem andern als dem Hauptthread auf das Property zugreifen, dann nur in einer Criticalsection.

Anders sieht es allerdings aus, wenn ich meine BilderDatenbank abfrage: Hier werden die Ergebnisse pro Datensatz in eine Klasse geschrieben (und diese in eine Objectliste gepackt), so dass die Abfrage selbst im Normalfall nur einmal durchgeführt werden muss.

Gruss
Delbor

sakura 3. Mär 2017 11:44

AW: Die Sache mit dem Listenproperty
 
Hi,

leider hast du offenbar überhaupt nicht verstanden, was ich geschrieben habe.

Zitat:

Zitat von Delbor (Beitrag 1363109)
Genaugenommen wird die Anfrage bei jedem lesezugriff auf das Property ausgeführt.

Korrekt.
Zitat:

Zitat von Delbor (Beitrag 1363109)
Die Alternative wäre, die SQL-Anfrage ausserhalb des Datenmoduls dann da ausführen, wo ich sie brauche.

Diese Änderung habe ich nicht einmal angedeutet, wäre mir auch nie in den Sinn gekommen.
Zitat:

Zitat von Delbor (Beitrag 1363109)
genau deswegen ist es besser, das Datenmodul stellt die Infos als Propery bereit.

Datenmodul ist eine einfache, nicht sehr schöne Lösung, aber praktikabel. Da wollte ich auch nicht ran.
Zitat:

Zitat von Delbor (Beitrag 1363109)
Und nochmals: sollte ich mit einem andern als dem Hauptthread auf das Property zugreifen, dann nur in einer Criticalsection.

Also zurück zu meiner Idee, welche DeddyH auch schon gut als Code gezeigt hat. Warum nicht einfach EINMAL die Daten ermitteln und anschließend einfach als fertige Liste zur Verfügung stellen. Gerne auch als TStrings - die Nach-/Vorteile sind ja bekannt. Dann würdest Du auch keine CS in multi-threading benötigen (mit der Einschränkung keiner ändert jemals die Werte nach dem initialen Befüllen).

Warum lädst Du mit jeder Anfrage sich nicht ändernde Daten neu? Das ist grundsätzlich kein gutes Vorgehen. Selbst wenn es schnell geht, macht es schnell einen spürbaren Unterschied in der Geschwindigkeit, je nachdem, wie oft das gemacht wird. :gruebel:

...:cat:...

Delbor 3. Mär 2017 13:23

AW: Die Sache mit dem Listenproperty
 
Hi Sakura

Ich hab mir DeddyHs Atwort zuunterst auf Seite eins nochmal angesehen. Meinst du die? Das könnte dann etwa so umgesetzt werden:
Delphi-Quellcode:
function TFDMySQLDml.GetContentmasterTables: TStringlist;
  var SqlString : String; I: integer;
begin
  if FContentmastertables = Nil then then
  begin
    FContentmastertables := Tstringlist.Create;
    SqlString := 'SHOW TABLES';
    FDQueryMain.Open(SqlString);
    FDQueryMain.First;
    while not FDQueryMain.Eof do
    begin
      FContentmastertables.Add(FDQueryMain.Fields.Fields[0].AsString);
      FDQueryMain.Next;
    end;
  FDQueryMain.Close;
  end;
  Result := (FContentmastertables);
 end;
Stimmt, so wird die Abfrage nur einmal durchgeführt, vorausgesetzt die Tabelle ändert sich nicht. Was sie allerdings zumindest zur Laufzeit nie tun sollte.

Gruss
Delbor

PS: Oder meinst du etwa dies aus Beitrag 18:
Zitat:

constructor TDingens.Create;
begin
FTablenames := TStringList.Create;
FillTablenamesFormSomewhere(FTablenames);
end;
Das gefällt nun mir nicht wirklich. Und DeddyH selbst wohl auch nicht.
Hier greift das Datenmudul nach oben*, was bei einer Trennung der Programmlogiken in verschiedene Schichten eben vermieden werden soll.

*Zumindest, wenn ich den Aufruf richtig interpretiere.

DeddyH 3. Mär 2017 18:31

AW: Die Sache mit dem Listenproperty
 
Kombinier doch einfach alles:
Delphi-Quellcode:
type
  TDingens = class
  private
    FTablenames: TStringList;
    function GetInternalTablenames: TStringList;
    function GetTablenames(Index: integer): string;
    function GetTablenameCount: integer;
    property InternalTablenames: TStringList read GetInternalTablenames;
  public  
    destructor Destroy; override;
    property TablenameCount: integer read GetTablenameCount;
    property Tablenames[Index: integer]: string read GetTablenames;
  end;

...

destructor TDingens.Destroy;
begin
  FTablenames.Free;
  inherited;
end;

function TDingens.GetInternalTablenames: TStringList;
begin
  if not Assigned(FTablenames) then
    begin
      FTablenames := TStringList.Create;
      (* Hier jetzt der Code zum Befüllen *)
    end;
  Result := FTablenames;
end;

function TDingens.GetTablenames(Index: integer): string;
begin
  //Hier wird auf die interne Property zugegriffen
  Result := InternalTablenames[Index];
end;

function GetTablenameCount: integer;
begin
  //Hier auch
  Result := InternalTablenames.Count;
end;

Delbor 4. Mär 2017 10:37

AW: Die Sache mit dem Listenproperty
 
Hi DeddyH

Hier habe ich zumindest unter FireDac ein Problem. In einer definierten Verbindung kann ich genau eine Datenbank angeben - zumindest muss ich das so interpretieren, nachdem Embarcadero in allen Definitionsbeispielen immer genau eine Datenbank angibt und dabei nichts von einer Verbindung zu mehreren Datenbanken dazuschreibt. Einzig Verbindungspooling bleibt da möglich zu sein.
Aber wie ich das bis jetzt verstanden habe, ist ein Pool eine Menge verschiedener Verbindungen, und ich denke, so würde dies auch der Server interpretieren. Und das führt dann dazu, dass jede Verbindung in diesem Pool aus Sicht des Servers ihre eigenen Sessionvariablen hat.

Als Beispiel die Veränderung des Wertes FMaxAllowedPacket. Die entsprechende Tabelle zeige ich mir so an:

Delphi-Quellcode:
'SELECT Variable_Value FROM performance_schema.SESSION_VARIABLES WHERE VARIABLE_NAME = ''MAX_ALLOWED_PACKET''';
Den Wert kann ich dann so ändern:

Delphi-Quellcode:
FDQueryMain.SQL.Text := 'SET @@global.Max_ALLOWED_PACKET = '+ IntToStr(Variable_Value);


Das akzeptiert der Server, weil es sich dabei um den Wert handelt, der für meine Verbindung gilt. Zumindest interpretie ich das so, da ich keine Rückmeldung wegen fehlender Rechte erhalte.
Ob das wirklich tut, was es soll, kann ich erst kontrollieren, wenn das Programm mal ohne AV startet.
Unter DBExpress hats funktioniert...

Führe ich nun aber ein einfaches 'Show Tables' aus, erhalte ich in jedem Fall die Tabellennamen der DB, mit der ich aktuell Verbunden bin. Das heisst aber, dass ich unter der aktuellen Verbindung nur lesend und mit einem SELECT-Statement auf die Serverdatenbank und deren Tabellen zugreifen kann.
Die Tabellennamen in in der DB performance_schema erhalte ich so nicht.

Aber nachdem ich mir deinen Code nochmal angeschaut habe: Ich bin offensichtlich noch nicht ganz wach. Dein Code zielt eigentlich auf das DRY-Prinzip ab. Mit meinem kurz davor geposteten Quelltext müsste ich die Passagen zur Erstellung der Liste jedesmal wiederholen.
Trotzdem lasse ich die ersten 3 Abschnitte jetzt mal stehen; vielleicht hat ja jemand eine Lösung, wie das Problem behoben werden könnte.

Auf jeden Fall mal vielen Dank für deinen Code!

Gruss
Delbor


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:21 Uhr.
Seite 3 von 3     123   

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