Einzelnen Beitrag anzeigen

Benutzerbild von MyRealName
MyRealName

Registriert seit: 19. Okt 2003
Ort: Heilbronn
673 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 21. Okt 2017, 16:36
Da fällt mir ein : dadurch dass du ja eine steuertabelle hast, kannst du naturlich dir den trigger code zusammenbauen on-the-fly wenn man die steuertabelle speichert und dann den trigger schreiben, also programmtechnisch schreiben und als script in die DB setzen.

ich habe das mal schnell geschrieben, musst man eventuell anpassen, habe UniDAC und EhLib genutzt und keine Komfort-Sachen reingeschrieben, also alles fest gecoded :

Code:
unit frmMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, DBGridEhGrouping, ToolCtrlsEh,
  DBGridEhToolCtrls, DynVarsEh, EhLibVCL, GridsEh, DBAxisGridsEh, DBGridEh,
  Vcl.StdCtrls, Vcl.ExtCtrls, UniProvider, InterBaseUniProvider, DBAccess, Uni, Data.DB, MemDS;

type
  TForm5 = class(TForm)
    UniConnection1: TUniConnection;
    UniTransaction1: TUniTransaction;
    InterBaseUniProvider1: TInterBaseUniProvider;
    Panel1: TPanel;
    ComboBox1: TComboBox;
    DBGridEh1: TDBGridEh;
    umdTables: TUniMetaData;
    Memo1: TMemo;
    umdCols: TUniMetaData;
    DataSource1: TDataSource;
    procedure FormShow(Sender: TObject);
    procedure UniConnection1AfterConnect(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
    procedure DBGridEh1SelectionChanged(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form5: TForm5;

implementation

{$R *.dfm}

procedure TForm5.FormShow(Sender: TObject);
begin
  UniConnection1.Connected := True;
  If UniConnection1.Connected Then begin
    umdTables.Active := True;
    While Not umdTables.Eof Do begin
      ComboBox1.Items.Add(umdTables.FieldByName('TABLE_NAME').AsString);
      umdTables.Next;
    end;
    umdTables.Close;
  end;
  If ComboBox1.Items.Count > 0 Then
    ComboBox1.ItemIndex := 0;
end;

procedure TForm5.UniConnection1AfterConnect(Sender: TObject);
begin
  UniTransaction1.StartTransaction;
end;

procedure TForm5.ComboBox1Change(Sender: TObject);
begin
  umdCols.Close;
  umdCols.Filtered := False;
  umdCols.Filter := 'TABLE_NAME=''' + ComboBox1.Text + '''';
  umdCols.Filtered := True;
  umdCols.Open;
end;

const TRIGGER_START : String = 'SET TERM ^ ; ' + #13#10 + #13#10 +
                               'CREATE OR ALTER TRIGGER TR_LOG_[TABLE_NAME] FOR [TABLE_NAME]' + #13#10 +
                               'ACTIVE AFTER UPDATE POSITION 100' + #13#10 +
                               'AS' + #13#10 +
                               'declare variable LogStr varchar(10000);' + #13#10 +
                               'begin' + #13#10 +
                               ' Logstr = '''';';
      TRIGGER_LOG_LINE : String = ' IF (NEW.DocId <> OLD.DocId) THEN' + #13#10 +
                                  '   Logstr = :LogStr || IIF(:LogStr <> '''', '','', '''') || ''"[FIELD_NAME]":'' || ''"'' || OLD.[FIELD_NAME] || ''"'';';
      TRIGGER_LOG_END : String = ' IF (:LogStr <> '''') THEN' + #13#10 +
                                 ' BEGIN' + #13#10 +
                                 '   LogStr = ''{ "CC": {'' || :LogStr || ''}}'';' + #13#10 +
                                 '   -- INSERT CODE HERE FOR WRITING INTO THE LOGGING TABLE' + #13#10 +
                                 ' end' + #13#10 +
                                 'end^' + #13#10 + #13#10 +
                                 'SET TERM ; ^';

procedure TForm5.DBGridEh1SelectionChanged(Sender: TObject);
var i: Integer;
    sLine : String;
begin
//  sTriggerName := 'TR_LOG_' + ComboBox1.Text; // TODO: delete everything longer than 31 chars
  Memo1.Clear;
  If DBGridEh1.SelectedRows.Count > 0 Then
    Memo1.Lines.Text := TRIGGER_START;
    Memo1.Lines.Text := StringReplace(Memo1.Lines.Text, '[TABLE_NAME]', ComboBox1.Text, [rfReplaceAll, rfIgnoreCase]);
    For i := 0 To DBGridEh1.SelectedRows.Count - 1 Do begin
      umdCols.GotoBookmark(TBookmark(DBGridEh1.SelectedRows.Items[i]));
      sLine := TRIGGER_LOG_LINE;
      sLine := StringReplace(sLine, '[FIELD_NAME]', umdCols.FieldByName('Column_name').AsString, [rfReplaceAll, rfIgnoreCase]);
      Memo1.Lines.Add(sLine);
    end;
    memo1.Lines.Add(TRIGGER_LOG_END)
end;

end.

Was macht der code :

Jedesmal wenn du ein Feld an- oder abwählst in der Tabelle wird der Trigger Code mit der aktuellen Feldliste erstellt, der einen JSON string erstellt mit den alten Werten, wenn was geändert wurde, Damit hast du in der Daten-Tabelle deine aktuelle Version der Daten und mit Zeitstempel rückwärts kannst du zum Ursprung zurückkehren.

man kann noch einen Delete trigger machen mit allen Feldern, wenn man will, damit man auch bei gelöschten Registern noch Daten hat

https://puu.sh/y3FJg/e1f21a30f9.png

Geändert von MyRealName (21. Okt 2017 um 19:10 Uhr) Grund: Code/Screenshot hinzugefügt
  Mit Zitat antworten Zitat