AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken DataSnap mit mehreren Datenbanken
Thema durchsuchen
Ansicht
Themen-Optionen

DataSnap mit mehreren Datenbanken

Ein Thema von Kostas · begonnen am 26. Mär 2015 · letzter Beitrag vom 28. Mär 2015
Antwort Antwort
Seite 2 von 2     12   
Kostas

Registriert seit: 14. Mai 2003
Ort: Gerstrhofen
1.095 Beiträge
 
Delphi 10 Seattle Enterprise
 
#11

AW: DataSnap mit mehreren Datenbanken

  Alt 27. Mär 2015, 15:10
Hallo himitsu,

oh man das klinkt wirklich kompliziert.
Wäre das eine Option?

Delphi-Quellcode:
function TdmServerMethodsZMI.ZMI_GetBauDataSetThreadSave(BauNr: integer): TDataSet;
var
  LDataSet: TDataSet;
begin
  TThread.Synchronize(nil, procedure
    var qrGetBau: TFDQuery;
    begin
      try
        qrGetBau:= TFDQuery.Create(nil);
        qrGetBau.Connection := dmZIMPool.conZMI;

        qrGetBau.SQL.Add('SELECT *');
        qrGetBau.SQL.Add('FROM BAU');
        qrGetBau.SQL.Add('WHERE BAUNR = :BAUNR');
        qrGetBau.Params[0].AsInteger := BauNr;

        qrGetBau.open;
        LDataSet := qrGetBau;
      finally
// qrGetBau.Free;
      end;
    end);
  Result := LDataSet;
end;

Geändert von Kostas (27. Mär 2015 um 16:13 Uhr)
  Mit Zitat antworten Zitat
Kostas

Registriert seit: 14. Mai 2003
Ort: Gerstrhofen
1.095 Beiträge
 
Delphi 10 Seattle Enterprise
 
#12

AW: DataSnap mit mehreren Datenbanken

  Alt 27. Mär 2015, 15:15
[QUOTE=Uwe Raabe;1295081]

Du kannst die Querys problemlos auf mehrere TDataModule-Klassen (nicht ServerMethods-Module!) aufteilen. Du musst diese halt jeweils zusammen mit der Instanz des ServerMethod-Moduls instantiieren und eine Connection thread-sicher (z.B. über den Connection-Pool wie in dem verlinkten Artikel) zuweisen. Damit entfällt halt die (leider zu bequeme) Möglichkeit, die Verknüpfungen der Komponenten zwischen verschiedenen Datenmodulen schon während des Designs herzustellen. Es muss halt für jede Instanz eines ServerMethod-Moduls auch der ganze Rattenschwanz der Query-Datenmodule instanziert werden.

Wenn du ein TDSServerModule verwendest und mit TDataSetProvider-Instanzen arbeitest, kannst du die jeweiligen DataSetProvider auf den zusätzlichen Datenmodulen über RegisterProvider dem TDSServerModule bekannt machen. Dann sind die im Client hinterher auch wiederzufinden.
Hallo Uwe,

das ist doch schon mal ein Lichtblick.
Warum gibt es keine Bücher über DataSnap. Das ist doch ein grosses Thema.
Dankeschön Uwe.

Gruß Kostas
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#13

AW: DataSnap mit mehreren Datenbanken

  Alt 27. Mär 2015, 18:50
Nach dem End geht dann DataSnap daher und läuft über das DataSet, daher ist alles darin, eventuell dennoch nicht threadsicher.

siehe z.B. Optionen ala Delphi-Referenz durchsuchenTFDAutoFetchAll, wo nach dem Open der DB-Zugrif noch nicht beendet sein kann.

Erstmal das Prinzip, ohne irgendeine Synchronisation (Synchronize oder CriticalSection), was man für threadsichere Dinge ala TFileStream benutzen kann.
Delphi-Quellcode:
function TdmServerMethodsZMI.ZMI_GetBauDataSetThreadSave(BauNr: Integer): TDataSet;
begin
  Result := TFDQuery.Create(nil);
  try
    Result.Connection := dmZIMPool.conZMI;
    Result.SQL.Add('SELECT *');
    Result.SQL.Add('FROM BAU');
    Result.SQL.Add('WHERE BAUNR = :BAUNR');
    Result.Params[0].AsInteger := BauNr;
    Result.Open;
  except
    FreeAndNil(Result);
    raise;
  end;
end;
Innerhalb mußt du selber die Sicherheit für deine Ressourcen sorgen
und nach dem End übernimmt das DataSnap (wenn es der Owner ist/wird)

Wenn man alles gekapselt hat, dann ginge es auch direkt, da Constructoren sich intern selber absicher. (wenn es knallt, wird automatisch Free Destroy aufgerufen)
Delphi-Quellcode:
function TdmServerMethodsZMI.ZMI_GetBauDataSetThreadSave(BauNr: Integer): TDataSet;
begin
  Result := TMyQuery.Create(nil, dmZIMPool.conZMI, 'SELECT * FROM BAU WHERE BAUNR = :BAUNR', [BauNr]);
end;
Mit einem Synchronize kann man sich überlegen wie man das absicher. (ersteres, wenn man blind davon ausgeht, daß der Rückweg vom Synchronize immer funktioniert)
Delphi-Quellcode:
function TdmServerMethodsZMI.ZMI_GetBauDataSetThreadSave(BauNr: Integer): TDataSet;
var
  LDataSet: TDataSet;
begin
  TThread.Synchronize(nil, procedure
    begin
      LDataSet := TFDQuery.Create(nil);
      try
        LDataSet.Connection := dmZIMPool.conZMI;
        LDataSet.SQL.Add('SELECT *');
        LDataSet.SQL.Add('FROM BAU');
        LDataSet.SQL.Add('WHERE BAUNR = :BAUNR');
        LDataSet.Params[0].AsInteger := BauNr;
        LDataSet.Open;
      except
        LDataSet.Free;
        raise;
      end;
    end);
  Result := LDataSet;
end;
Delphi-Quellcode:
function TdmServerMethodsZMI.ZMI_GetBauDataSetThreadSave(BauNr: Integer): TDataSet;
var
  LDataSet: TDataSet;
begin
  LDataSet := nil;
  try
    TThread.Synchronize(nil, procedure
      begin
        LDataSet := TFDQuery.Create(nil);
        LDataSet.Connection := dmZIMPool.conZMI;
        LDataSet.SQL.Add('SELECT *');
        LDataSet.SQL.Add('FROM BAU');
        LDataSet.SQL.Add('WHERE BAUNR = :BAUNR');
        LDataSet.Params[0].AsInteger := BauNr;
        LDataSet.Open;
      end);
  except
    LDataSet.Free;
    raise;
  end;
  Result := LDataSet;
end;
PS: Create gehört natürlich grundsätzlich immer vor das Try, denn wenn es im Create knallt, dann ist im Finally/Except die Variable nicht initialisiert,
was einem der Compiler aber auch sagt, wenn man mal liest was der zu sagen kannt.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (27. Mär 2015 um 22:10 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#14

AW: DataSnap mit mehreren Datenbanken

  Alt 27. Mär 2015, 20:38
@himitsu

Warum ein try .. except wo ein try .. finally reicht?
Vor allem im letzten Beispiel lieferst du bei einer Exception eine ungültige Referenz zurück.

So ist es sauber:
Delphi-Quellcode:
LDataSet := TFDQuery.Create;
try
  ...
  Result := LDataSet;
  LDataSet := nil;
finally
  LDataSet.Free;
end;
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#15

AW: DataSnap mit mehreren Datenbanken

  Alt 27. Mär 2015, 22:08
Weil das logischier und vorallem verständlicher ist?
> Wenn es knallt, dann gibt es wieder frei?

Andersrum muß man vorher erstmal gucken/wissen was damit gemacht wurde (an wen anderes zuweisen und auf nil setzen),
aber auf den ersten Blick heißt es erstmal nur
> Gib es immer frei, selbst wenn es erfolgreich war.

Vor allem im letzten Beispiel lieferst du bei einer Exception eine ungültige Referenz zurück.
Nein, denn bei einer Exception kommt der Code bei der Zuweisung nicht mehr vorbei.

[edit]
Ups, hatte was vergessen, aber das hat ja keiner gemerkt.
(Copy&Paste im kleinen DP-Beitragseditor ist das Beste)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (27. Mär 2015 um 22:12 Uhr)
  Mit Zitat antworten Zitat
Kostas

Registriert seit: 14. Mai 2003
Ort: Gerstrhofen
1.095 Beiträge
 
Delphi 10 Seattle Enterprise
 
#16

AW: DataSnap mit mehreren Datenbanken

  Alt 28. Mär 2015, 17:16
Hallo zusammen,

ich habe nun ein neues DataSnapServer-/Client Projekt aufgesetzt und dabei das Prinzip Connection Pooling eingesetzt.
Ein DataSet kann auch "ThreadSave" vom Client abgerufen werden. Es scheint alles zu funktionieren.


Wenn der Server ein DataSet bereit stellt, darf die Connection am Ende nicht beenden werden.
Ich darf auch nicht die Connection und die Query am ende auf Free setzen. Ist das so in Ordnung?
Setze ich es auf Free, bekommt der Client nix.

Ist die Methode soweit ausreichend ThreadSave?


Delphi-Quellcode:
function TdmDALZMI.GetBau(BauNr: integer): TDataSet;
var
  oConn: TFDConnection;
  oQuery: TFDQuery;
begin
  oQuery := nil;

  oConn := TFDConnection.Create(nil);
  oQuery := TFDQuery.Create(nil);
  try
    TThread.Synchronize(nil, procedure
    begin
      oConn.ConnectionDefName := ZMIConnectionDefName; //<<<<< Der ConnectionManager möchte unbedingt über ConnectionDefName gebunden werden damit Pooling funktioniert.
      oQuery.Connection := oConn;
      oQuery.FetchOptions.AutoFetchAll := afAll; //<< Alle Record sollen vollständig abgerufen werden

      oQuery.SQL.Text := 'SELECT * FROM BAU WHERE BAUNR = :BAUNR';
      oQuery.Params[0].AsInteger := BauNr;
      oQuery.Open;
// oConn.Close; //<<<<<<<<<<<<<<<< Ist das OK?
    end);

    result := oQuery;
  finally
// oQuery.Free; //<<<<<<<<<<<<<<<< Ist das OK?
// oConn.Free; //<<<<<<<<<<<<<<<<
  end;

end;

Clientseitig wird das DataSet so abgerufen und in eine TFDMemTable copiert:
Delphi-Quellcode:

procedure TdmZMI.GetBauDataSet(BauNr: integer);
var
  LZMIClient: TdmServerMethodsZMIClient;
  LDataSet: TDataSet;

begin
  LZMIClient := TdmServerMethodsZMIClient.Create(dmClientContainer.CMCSQLConnection.DBXConnection);
  try
    LDataSet := LZMIClient.GetBau(BauNr);
    mtBau.Active := False;
    mtBau.CopyDataSet(LDataSet, [coStructure, coRestart, coAppend]);
    mtBau.Open;
  finally
    LZMIClient.Free;
  end;

end;

Gruß Kostas
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#17

AW: DataSnap mit mehreren Datenbanken

  Alt 28. Mär 2015, 18:27
Die Query kann so vom DataSnap (Result + OwningResults) freigegeben werden,
aber wer gibt die Connection frei?

Entweder du leitest die Query ab und baust die Connection dort ein, oder du benutzt die Query als Owner.
Delphi-Quellcode:
Result := TFDQuery.Create(nil);
try
  oConn := TFDConnection.Create(Result);
  oConn.ConnectionDefName := ZMIConnectionDefName;
  Result.Connection := oConn;
  Result.FetchOptions.AutoFetchAll := afAll;
  Result.SQL.Text := 'SELECT * FROM BAU WHERE BAUNR = :BAUNR';
  Result.Params[0].AsInteger := BauNr;
  Result.Open;
except
  Result.Free; // freigeben, wenn es beim Erstellen und vorallem im Open Probleme gab. (Tabelle/Feld nicht gefunden)
  raise;
end;
Und natürlich darf die Query am Ende nicht freigegeben oder geschlossen werden, denn es soll ja deren Inhalt am Ende noch übertragen werden und dafür mit die Query existieren und vorallem auch Daten enthalten.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Kostas

Registriert seit: 14. Mai 2003
Ort: Gerstrhofen
1.095 Beiträge
 
Delphi 10 Seattle Enterprise
 
#18

AW: DataSnap mit mehreren Datenbanken

  Alt 28. Mär 2015, 20:25
Hallo himitzu,

das mit dem Result als TFDQuery schein nicht zu funktionieren. Der Compiler
meckert, "Symbol Result kann nicht erfasst werden" innerhalb der anonymen Thread Methode.

Delphi-Quellcode:
function TdmDALZMI.GetBau(BauNr: integer): TDataSet;
var
  oConn: TFDConnection;
// oQuery: TFDQuery;
begin
// oQuery := nil;
  Result := TFDQuery.Create(nil);

  oConn := TFDConnection.Create(nil);
// oQuery := TFDQuery.Create(nil);
  try
    TThread.Synchronize(nil, procedure
    begin
      oConn.ConnectionDefName := ZMIConnectionDefName;
      Result.Connection := oConn; //<<<geht nicht
      Result.FetchOptions.AutoFetchAll := afAll;

      Result.SQL.Text := 'SELECT * FROM BAU WHERE BAUNR = :BAUNR';
      Result.Params[0].AsInteger := BauNr;
      Result.Open;
// oConn.Close;
    end);

// result := oQuery;
  except
    result.Free;
// oConn.Free;
  end;

end;

Wegen dem Connection Objekt, als ich umgestellt habe, bin ich nach dem Beispiel Pooling von FireDAC
vorgegangen. Hier wird eine Connection instanziiert allerdings auch wieder freigeben!

Mit nicht freigeben von Objekten bin ich nicht Sattelfest. Ich kann das noch nicht greifen.
Aber wenn es funktioniert, ist mir das auch recht.
Eigentlich hätte ich erwartet dass das Connection Objekt über den ConnectionManager gemanagt wird.

Delphi-Quellcode:
procedure TConnectThread.Execute;
var
  oConn: TFDConnection;
  oQuery: TFDQuery;
  i: Integer;
begin
  oConn := TFDConnection.Create(nil);
  oQuery := TFDQuery.Create(nil);
  try
    oQuery.Connection := oConn;
    oConn.ConnectionDefName := FForm.cbDB.Text;
    for i := 1 to 50 do begin
      oQuery.SQL.Text := 'select count(*) from {id Region}';
      oQuery.Open;
      oConn.Close;
      Synchronize(FForm.Executed);
    end;
  finally
    oConn.Free;
    oQuery.Free;
  end;
end;

Leider kann ich nicht nachvollziehen wie du es gemeint hast mit Query als Owner.
Wenn es deine Zeit erlaubt, würdest du das bitte kurz beschreiben.


Gruß Kostas

Geändert von Kostas (28. Mär 2015 um 20:28 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#19

AW: DataSnap mit mehreren Datenbanken

  Alt 28. Mär 2015, 21:02
Wenn eine Variable nicht erfasst werden kann, dann mit einer TempVariable dazwischen arbeiten.

Mit Owner meinte ich das so
Delphi-Quellcode:
oQuery := TFDQuery.Create(nil); // in der Methode mit Try-Except gesichert und danach wird DateSnap der Owner des Result
oConn := TFDConnection.Create(oQuery); // die FDQuery übernimmt die Kontrolle der Freigabe
Hier kommt doch nur noch ConnectionDefName von außerhalb.
Alles Andere ist intern und wäre somit threadsave.
Wenn der Wert ConnectionDefName aus einem String kommt (die sind beim Lesen threadsave, solange es keine externen Änderungen gibt), dann geht das auch so,
ansonsten müsste man eigentlich nur noch diesen Zugriff absichern.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (28. Mär 2015 um 21:06 Uhr)
  Mit Zitat antworten Zitat
Kostas

Registriert seit: 14. Mai 2003
Ort: Gerstrhofen
1.095 Beiträge
 
Delphi 10 Seattle Enterprise
 
#20

AW: DataSnap mit mehreren Datenbanken

  Alt 28. Mär 2015, 21:44
Hallo himitzu,

jetzt läuft alles einwandfrei und Sau schnell.
Ohne die Sache mit dem Owner, konnte ich maximal 50 Anfragen stellen da die Default Connections Anzahl bei
50 steht. Somit ist klar, die Connection waren aktiv! Mit dem Owner gibt es nun keine Limitierung.
Zugleich habe ich die Bestätigung dass das Query Objekt von "Geisterhand" selbstständig eliminiert wird
nach dem Transfer da damit auch die Connection eliminiert wird.

Das ist doch wie Weihnachten und Ostern an einem Tag.
Ich bin dir sehr dankbar und weis das auch zu schätzen.

Gruß Kostas
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:30 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