Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Wie kann man mit tiOPF Generatoren nutzen (https://www.delphipraxis.net/147066-wie-kann-man-mit-tiopf-generatoren-nutzen.html)

DelphiBandit 1. Feb 2010 10:53

Datenbank: Firebird • Version: 1.5 • Zugriff über: IBX / UIB

Wie kann man mit tiOPF Generatoren nutzen
 
Hallo zusammen,

ich arbeite mich gerade in die Nutzung des tiOPF-Frameworks ein. Soweit habe ich das auch alles installiert und alle Demo's zum Laufen bekommen. Da google hierzu auch nicht sonderlich hilfreich ist, möchte ich meine Frage mal bei Euch loswerden - in der Hoffnung es nutzt noch jemand tiOPF.

Es gibt in der Firebird-Datenbank (V1.5) sehr viele Tabellen, welche die ihren Primärschlüssel ID haben. Dieser wird in der bestehenden Anwendung durch Zuweisung von "GEN_ID(GEN_NAME, 1) FROM RDB$DATABASE" gefüllt. Jetzt versuche ich diese Logik auf tiOPF umzusetzen, finde aber bisher keinen geeigneten Weg dazu.

Mein erster Schritt war dabei die Anlage eines Hard-Coded-Visistors um das ID-Feld auf die interne OID abzubilden. Laden, Selektieren, Editieren, Speichern und Löschen funktioniert auch einwandfrei. Nur beim Einfügen von neuen Datensätzen finde ich keinen Ansatz nach dem Speichern eines neuen Datensatz dessen generierte (Trigger/Generator) ID herauszufinden.

Die angegebene SQL-Anweisung für den Create-Visitor funktioniert auch, allerdings komme ich nicht an die erzeugte ID heran. Die bräuchte ich aber in der Folge, damit tiOPF seinen Datensatz wiedererkennen kann. Neu laden aller Datensätze wäre ein Ansatz, kostet aber bei vielen Datensätzen Performance ohne Ende. Oder das Neu-Lesen mit Maximum(ID), wobei andere User mittlerweile auch Datensätze angelegt haben könnten. Also auch keine gute Idee.

Hat jemand von Euch damit schon Erfahrungen gemacht oder eine Tipp dazu?

Gruss
Carsten

Delphi-Quellcode:
{ TVisName_Create }

function TVisName_Create.AcceptVisitor: boolean;
begin
  result := (Visited is TPName) and
    (Visited.ObjectState = posCreate);
  Log([ClassName, Visited.ClassName, Visited.ObjectStateAsString, Result]);
end;

procedure TVisName_Create.Init;
begin
  Query.SQLText :=
    'INSERT INTO TEST (NACHNAME, VORNAME) VALUES (:NACHNAME, :VORNAME)';
end;

procedure TVisName_Create.SetupParams;
var
  lData: TPName;
begin
  lData := Visited as TPName;
  // OID braucht nicht gefüllt werden, das erledigt der Trigger automatisch
  Query.ParamAsString['Nachname'] := lData.Nachname;
  Query.ParamAsString['Vorname'] := lData.Vorname;
end;

Blup 1. Feb 2010 13:10

Re: Wie kann man mit tiOPF Generatoren nutzen
 
Auch wenn der Trigger die ID automatisch vergeben kann, ist es in diesem Fall besser die ID vor dem Insert zu erzeugen.

Ein denkbarer Weg wäre, wäre bei der Datenklasse ein eigener "constructor CreateNew()" dem der Generatorname mit übergeben wird und eine eigene Generatorklasse beim GTIOPFManager registrieren, die mit diesem Parameter etwas anfangen kann.

DelphiBandit 2. Feb 2010 08:13

Re: Wie kann man mit tiOPF Generatoren nutzen
 
Gute Anregung - habe mir jetzt eine Generatorklasse geschrieben, welche den Wert aktuell beim Belegen des Objektes in CreateNew bestimmt. Das ist momentan noch sehr rudimentär ohne ttiObjectList drumherum, mit der ich sicherlich die ganzen benötigten Generatoren in einer Art Collection halten könnte.

Aber zum weiteren testen bezüglich Umstellungsaufwand funktioniert es jetzt erstmal mit kurzzeitigem Erzeugen des Generator-Objektes und belegen der OID mit dem Generatorwert.

Danke nochmal für den Tipp, hast Du da ggf. schon etwas ausgefeilteres gebaut?

Carsten


und vielleicht kann es nochmal jemand brauchen, deshalb hier mein Denkansatz

Delphi-Quellcode:
// Grundklasse
uses
  Classes
  ,SysUtils
  ,Windows
  ,tiObject
  ,Generator_HCV
  ,Generator_BOM
  ;
....
// Beispielaufruf in CreateNew des eigentlichen Tabellenobjektes
constructor TPName.CreateNew(const ADatabaseName,
  APersistenceLayerName: string);
var lGen: TPGenerator;
begin
  inherited Create;
  // Get an ID from Generator
  lGen := TPGenerator.Create;
  lGen.GeneratorName := 'GEN_TEST_ID';
  lGen.ObjectState := posCreate;
  lGen.Read; // Stösst Read in Generator_HCV an und belegt OID aus dem Generator

  OID.AsVariant := lGen.OID.AsVariant;
  lGen.Free;
end;

// Quelltext Generator_BOM.pas
unit Generator_BOM;

interface

uses
  Classes
  ,SysUtils
  ,Windows
  ,tiObject
  ;

const
  cErrorGeneratorNameMissing = 'Kein GeneratorName bekannt!';

type
  TPGenerator = class(TtiObject)
  private
    FGeneratorName: string;
  protected
  public
    function IsValid(const AErrors: TtiObjectErrors): boolean; override;
    procedure Read; overload;
  published
    property GeneratorName: string read FGeneratorName write FGeneratorName;
  end;

implementation

uses
  tiOPFManager
  , tiOIDInteger
  ;

{ TPGenerator }
function TPGenerator.IsValid(const AErrors: TtiObjectErrors): boolean;
begin
  inherited IsValid(AErrors);

  if Trim(GeneratorName) = '' then
    AErrors.AddError('GeneratorName', cErrorGeneratorNameMissing);

  result := AErrors.Count = 0;
end;

procedure TPGenerator.Read;
begin
  inherited Read;
end;

end.

// Quelltext Generator_HCV.pas
unit Generator_HCV;

interface
uses
  tiVisitorDB
  ;

type
  TVisGenerator_Read = class(TVisOwnedQrySelect)
  protected
    function AcceptVisitor: boolean; override;
    procedure Init; override;
    procedure SetupParams; override;
    procedure MapRowToObject; override;
  end;

procedure RegisterVisitors;

implementation
uses
  Generator_BOM
  , tiOPFManager
  , tiObject
  , tiLog
  , tiCriteria
  , tiVisitorCriteria
  ;

procedure RegisterVisitors;
begin
  GTIOPFManager.RegReadVisitor(TVisGenerator_Read);
end;

{ TVisClient_Read }
procedure TVisGenerator_Read.MapRowToObject;
var
  lGenerator: TPGenerator;
begin
  lGenerator := TPGenerator(Visited);
  lGenerator.OID.AsVariant := Query.FieldAsIntegerByIndex[0];
  lGenerator.ObjectState := posClean;
end;

function TVisGenerator_Read.AcceptVisitor: boolean;
begin
  result := (Visited is TPGenerator) and
    (Visited.ObjectState = posCreate);
  Log([ClassName, Visited.ClassName, Visited.ObjectStateAsString, Result]);
end;

procedure TVisGenerator_Read.Init;
var
  lData: TPGenerator;
begin
  lData := TPGenerator(Visited);

  Query.SQLText := 'SELECT GEN_ID(' + lData.GeneratorName + ',1) FROM RDB$DATABASE';
end;

procedure TVisGenerator_Read.SetupParams;
begin
  ;
end;

end.

schlecki 2. Feb 2010 08:50

Re: Wie kann man mit tiOPF Generatoren nutzen
 
auch ein netter Weg ist (allerdings nur bei Firebird ab 2.1 glaube ich):

SQL-Code:
insert into Table (ID, ...) values (null, ...) returning ID
vielleicht muß man dann noch einen Parameter erzeugen, hängt von den verwendeten Komponenten ab - achja und einen Trigger brauchst du, der ID mit NULL automatisch generiert...

Delphi-Quellcode:
var
  p: TParam;
begin
  qry.SQL.Text := '... returning ID';
  p := TParam.Create;
  p.ParamType := ptOutput;
  p.DataType := ftInteger;
  qry.Params.Add(p);
  qry.Execute;

  ID := qry.ParamByName('ID').AsInteger;
end;
Also zumindest mit den Komponenten, die wir bei uns einsetzen, geht das...

DelphiBandit 2. Feb 2010 09:01

Re: Wie kann man mit tiOPF Generatoren nutzen
 
Zitat:

Zitat von schlecki
auch ein netter Weg ist (allerdings nur bei Firebird ab 2.1 glaube ich)

Ja, das mit dem Returning war mir schon bekannt. Habe das im Prinzip mit StoredProcs (für Insert) nachgebaut, die im Output einen Wert für die ID zurückliefern. Umständlich, aber das gleiche Ergebnis :)

Geht tatsächlich erst ab 2.x, da wir hauptsächlich 1.5 Datenbanken installiert haben, fällt das momentan aus.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:13 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