Avatar billede hugopedersen Nybegynder
07. februar 2014 - 17:15 Der er 6 kommentarer og
1 løsning

Umulig opgave eller hvad?

Jeg har en næsten umulig opgave - jeg kan i hvert fald ikke lige se løsningen :-)

Jeg har en Logbook klasse jeg tildeler nogle værdier og så skriver jeg en entry i en tabel i en DB f.eks.

procedure TfrmMain.Button2Click(Sender: TObject);
var
  Logbook: TLogbook;
begin
  Logbook := TLogbook.Create;
  try
    Logbook.EntryDate    := Date;
    Logbook.EntryText    := 'Sendt email til en eller anden';
    Logbook.EntryType    := GuidLogbookMail;
    Logbook.EntryContact  := GuidEmpty;
    Logbook.Save;
  finally
    Logbook.Free;
  end;
end;

Nu vi jeg så gerne bruge en udvidet version af den klasse i et andet program. Udvidelsen består i at der er nogle flere felter der skal udfyldes i databasen.
Jeg kan godt lave udvidelsen med nye properties o.s.v. men hvordan pokker får man den til at skrive de ekstra felter?
Kan det kun gøres ved at lave en ny .Save procedure der indeholder koden fra TLogbook + det ekstra og så lade den override den fra TLogbook?

Håber denne forklaring giver mening.
Avatar billede arne_v Ekspert
08. februar 2014 - 04:56 #1
Hvis du ikke kan aendre i din original klasse, saa laver du en ny tabel med de nye felter og en foreign key til den originale tabel og lader den extended klasses Save kalde base Save og gemme de ekstra felter i den nye tabel.

Lige ud af landevejen.
Avatar billede arne_v Ekspert
08. februar 2014 - 04:57 #2
Hvis du kan aendre lidt i original klassen, saa kan du udnytte OOP.

Demo (med lidt generelle navne):


type
  Original = class
  public
    procedure Save;
    function GetSQL : string; virtual;
    procedure AddParams(q : TSQLQuery); virtual;
  private
    v1 : integer;
    v2 : integer;
    con : TSQLConnection;
  end;
  Extended = class(Original)
  public
    function GetSQL : string; override;
    procedure AddParams(q : TSQLQuery); override;
  private
    v3 : integer;
  end;

procedure Original.Save;

var
  q : TSQLQuery;

begin
  q := TSQLQuery.Create(nil);
  q.DataBase := con;
  q.SQL.Text := GetSQL;
  AddParams(q);
  q.ExecSQL;
  q.Free;
end;

function Original.GetSQL : string;

begin
  GetSQL := 'INSERT INTO logtbl (v1,v2) VALUES(:v1,:v2)';
end;

procedure Original.AddParams(q : TSQLQuery);

begin
  q.Params.ParamByName('v1').AsInteger := v1;
  q.Params.ParamByName('v2').AsInteger := v2;
end;

function Extended.GetSQL : string;

begin
  GetSQL := 'INSERT INTO logtbl (v1,v2,v3) VALUES(:v1,:v2,:v3)';
end;

procedure Extended.AddParams(q : TSQLQuery);

begin
  inherited AddParams(q);
  q.Params.ParamByName('v3').AsInteger := v3;
end;
Avatar billede arne_v Ekspert
08. februar 2014 - 04:58 #3
Og det er saa utestet, men ideen boer fremgaa.
Avatar billede hugopedersen Nybegynder
10. februar 2014 - 15:35 #4
Har ikke glemt dig - men er lige optaget af noget andet som er vigtigere :-)
Avatar billede arne_v Ekspert
11. februar 2014 - 01:59 #5
En variation:


type
  Original = class
  public
    procedure Save;
    procedure AddFields(fldlst : TStringList); virtual;
    procedure AddParams(q : TSQLQuery); virtual;
  private
    v1 : integer;
    v2 : integer;
    con : TSQLConnection;
  end;
  Extended = class(Original)
  public
    procedure AddFields(fldlst : TStringList); override;
    procedure AddParams(q : TSQLQuery); override;
  private
    v3 : integer;
  end;

procedure Original.Save;

var
  fldlst : TStringList;
  sqlstr : string;
  q : TSQLQuery;
  i : integer;

begin
  fldlst := TStringList.Create;
  AddFields(fldlst);
  sqlstr := 'INSERT INTO logtbl(';
  for i := 0 to fldlst.Count-1 do begin
      if i > 0 then sqlstr := sqlstr + ',';
      sqlstr := sqlstr + fldlst[i];
  end;
  sqlstr := sqlstr + ') VALUES(';
  for i := 0 to fldlst.Count-1 do begin
      if i > 0 then sqlstr := sqlstr + ',';
      sqlstr := sqlstr + ':' + fldlst[i];
  end;
  sqlstr := sqlstr + ')';
  q := TSQLQuery.Create(nil);
  q.DataBase := con;
  q.SQL.Text := '';
  AddParams(q);
  q.ExecSQL;
  q.Free;
end;

procedure Original.AddFields(fldlst : TStringList);

begin
  fldlst.Add('v1');
  fldlst.Add('v2');
end;

procedure Original.AddParams(q : TSQLQuery);

begin
  q.Params.ParamByName('v1').AsInteger := v1;
  q.Params.ParamByName('v2').AsInteger := v2;
end;

procedure Extended.AddFields(fldlst : TStringList);

begin
  inherited AddFields(fldlst);
  fldlst.Add('v3');
end;

procedure Extended.AddParams(q : TSQLQuery);

begin
  inherited AddParams(q);
  q.Params.ParamByName('v3').AsInteger := v3;
end;
Avatar billede hugopedersen Nybegynder
16. februar 2014 - 12:11 #6
Efter at have kigget på forskellige forslag og ideer, er jeg kommet frem til en løsning der måske ikke er den mest elegante, men den virker og jeg har de muligheder jeg ønsker.

(Jeg bruger UniDAC til databaseadgang og så er der nok fedtet et par at mine andre units ind i det også)

Smid et svar Arne så får du point for dine input.


unit U_Logbook;

interface

uses
{$Include UniDACCommon.inc}
  Db, MemDS, DbAccess, Uni,
  Classes;

{$M+}

type
  TLogbook = Class
  private
    fEntryGuid: string;
    fEntryDate: TDate;
    fEntryType: string;
    fEntryText: string;
    fEntryContact: string;

    procedure SetText(const Value: string);
  protected
    procedure AddFields; virtual;
    procedure AddParams; virtual;
    procedure AddValues; virtual;
  published
    fQuery: TUniQuery;
    constructor Create;
    destructor Destroy; override;

    property EntryGuid: string read fEntryGuid write fEntryGuid;
    property EntryDate: TDate read fEntryDate write fEntryDate;
    property EntryType: string read fEntryType write fEntryType;
    property EntryText: string read fEntryText write SetText;
    property EntryContact: string read fEntryContact write fEntryContact;
  public
    procedure Save;
  end;

const
  GuidLogbookMail = '{11111111-1111-1111-1111-111111111111}';
  NewLogText      = 'Ny log post!';

implementation

uses
  System.SysUtils, System.StrUtils, System.DateUtils,
  Vcl.Forms, Vcl.Dialogs, Vcl.Controls,
  F_UniConn,
  U_FormatSettingsHelper,
  U_Logfile, U_Utilities, U_Network,
  U_LogbookDb, U_User;

{ TLogbook }
constructor TLogbook.Create;
begin
  inherited;
  fQuery            := frmUniConn.CreateQuery;

  fEntryGuid        := GuidEmpty;
  fEntryDate        := Date;
  fEntryType        := GuidEmpty;
  fEntryText        := '';
  fEntryContact    := GuidEmpty;
end;

destructor TLogbook.Destroy;
begin
  try
    if fQuery.SQL.Text <> '' then
      fQuery.Execute;
  finally
    fQuery.Free;
    inherited;
  end;
end;

procedure TLogbook.AddFields;
begin
  try
    fQuery.SQL.Clear;
    fQuery.SQL.Add('INSERT INTO ' + TableLogbook);
    fQuery.SQL.Add(' ( ');
    fQuery.SQL.Add('  fldlog_guid');
    fQuery.SQL.Add('  ,fldlog_day');
    fQuery.SQL.Add('  ,fldlog_date');
    fQuery.SQL.Add('  ,fldlog_year');
    fQuery.SQL.Add('  ,fldlog_month');
    fQuery.SQL.Add('  ,fldlog_week');
    fQuery.SQL.Add('  ,fldlog_text');
    fQuery.SQL.Add('  ,fldlog_type');
    fQuery.SQL.Add('  ,fldlog_contact');
    fQuery.SQL.Add('  ,fldcreated_computer');
    fQuery.SQL.Add('  ,fldcreated_by');
    fQuery.SQL.Add('  ,fldcreated_date');
    fQuery.SQL.Add('  ,fldupdated_computer');
    fQuery.SQL.Add('  ,fldupdated_by');
    fQuery.SQL.Add('  ,fldupdated_date');
  except
    on E:exception do
      Logfile.Error('U_Logbook.AddFields: ' + E.Message);
  end;
end;

procedure TLogbook.AddParams;
begin
  try
    fQuery.SQL.Add(' ) values ( ');
    fQuery.SQL.Add('  :fldlog_guid');
    fQuery.SQL.Add(' ,:fldlog_day');
    fQuery.SQL.Add(' ,:fldlog_date');
    fQuery.SQL.Add(' ,:fldlog_year');
    fQuery.SQL.Add(' ,:fldlog_month');
    fQuery.SQL.Add(' ,:fldlog_week');
    fQuery.SQL.Add(' ,:fldlog_text');
    fQuery.SQL.Add(' ,:fldlog_type');
    fQuery.SQL.Add(' ,:fldlog_contact');
    fQuery.SQL.Add(' ,:fldcreated_computer');
    fQuery.SQL.Add(' ,:fldcreated_by');
    fQuery.SQL.Add(' ,:fldcreated_date');
    fQuery.SQL.Add(' ,:fldupdated_computer');
    fQuery.SQL.Add(' ,:fldupdated_by');
    fQuery.SQL.Add(' ,:fldupdated_date');
  except
    on E:exception do
      Logfile.Error('U_Logbook.AddParams: ' + E.Message);
  end;
end;

procedure TLogbook.AddValues;
var
  myYear, myMonth, myDay: Word;
  myHour, myMin, mySec, myMilli : Word;
  LogTime: TDate;
begin
  try
    fQuery.SQL.Add(' ) ');
    fQuery.ParamByName('fldlog_guid').AsString                      := GuidCreate;
    fQuery.ParamByName('fldlog_day').AsString                      := FormatSettings.ISOLongDayNames(DayOfTheWeek(fEntryDate));
    fQuery.ParamByName('fldlog_date').AsDateTime                    := fEntryDate;
    fQuery.ParamByName('fldlog_year').AsInteger                    := YearOf(fEntryDate);
    fQuery.ParamByName('fldlog_month').AsInteger                    := MonthOf(fEntryDate);
    fQuery.ParamByName('fldlog_week').AsInteger                    := WeekOf(fEntryDate);
    fQuery.ParamByName('fldlog_text').AsString                      := fEntryText;
    fQuery.ParamByName('fldlog_type').AsString                      := fEntryType;
    fQuery.ParamByName('fldlog_contact').AsString                  := fEntryContact;
    fQuery.ParamByName('fldcreated_computer').AsString              := Network.ComputerName;
    fQuery.ParamByName('fldcreated_by').AsString                    := User.ID;
    fQuery.ParamByName('fldupdated_computer').AsString              := Network.ComputerName;
    fQuery.ParamByName('fldupdated_by').AsString                    := User.ID;

    LogTime := DateOf(fEntryDate);
    DecodeDate(LogTime, myYear, myMonth, myDay);
    DecodeTime(Now, myHour, myMin, mySec, myMilli);
    LogTime := EncodeDateTime(myYear, myMonth, myDay, myHour, myMin, mySec, myMilli);
    fQuery.ParamByName('fldcreated_date').AsDateTime                := LogTime;
    fQuery.ParamByName('fldupdated_date').AsDateTime                := LogTime;
  except
    on E:exception do
      Logfile.Error('U_Logbook.AddValues: ' + E.Message);
  end;
end;

procedure TLogbook.Save;
begin
  try
    AddFields;
    AddParams;
    AddValues;
  except
    on E:exception do
      Logfile.Error('U_Logbook.Save: ' + E.Message);
  end;
end;


// Getters and setters
procedure TLogbook.SetText(const Value: string);
begin
  if Value = '' then
    fEntryText := NewLogText
  else
    fEntryText := Value;
end;


end.

Jeg har så en unit der arver noget:

unit U_JsLogbook;

interface

uses
{$Include UniDACCommon.inc}
  Db, MemDS, DbAccess, Uni,
  U_Logbook,
  Classes;

{$M+}

type
  TJsLogbook = Class(TLogbook)
  private
    fEntryFirst: boolean;
    fEntryApplication: string;
    fEntryPosition: string;
    fEntrySection: string;

    procedure SetPosition(const Value: string);
    procedure SetSection(const Value: string);
  protected
    procedure AddFields; override;
    procedure AddParams; override;
    procedure AddValues; override;
  published
    constructor Create;
    destructor Destroy; override;

    property EntryFirst: boolean read fEntryFirst write fEntryFirst;
    property EntryApplication: string read fEntryApplication write fEntryApplication;
    property EntryPosition: string read fEntryPosition write SetPosition;
    property EntrySection: string read fEntrySection write SetSection;
  public
    function Save: string;
    procedure Update;
  end;

var
  JsLogbook: TJsLogbook;

implementation

uses
  System.UITypes, System.SysUtils, System.StrUtils, System.DateUtils,
  Vcl.Forms, Vcl.Dialogs, Vcl.Controls,
  U_FormatSettingsHelper,
  F_UniConn,
  U_Logfile, U_Network, U_Utilities,
  U_LogbookDb, U_User;

{ TJsLogbook }
constructor TJsLogbook.Create;
begin
  inherited;
  fEntryFirst      := False;
  fEntryApplication := GuidEmpty;
  fEntrySection    := GuidEmpty;
  fEntryPosition    := GuidEmpty;
end;

destructor TJsLogbook.Destroy;
begin
  try
  finally
    inherited;
  end;
end;

procedure TJsLogbook.AddFields;
begin
  inherited;
  try
    fQuery.SQL.Add('  ,fldlog_firstentry');
    fQuery.SQL.Add('  ,fldlog_application');
    fQuery.SQL.Add('  ,fldlog_section');
    fQuery.SQL.Add('  ,fldlog_position');
  except
    on E:exception do
      Logfile.Error('U_JsLogbook.AddFields: ' + E.Message);
  end;
end;

procedure TJsLogbook.AddParams;
begin
  inherited;
  try
    fQuery.SQL.Add(' ,:fldlog_firstentry');
    fQuery.SQL.Add(' ,:fldlog_application');
    fQuery.SQL.Add(' ,:fldlog_section');
    fQuery.SQL.Add(' ,:fldlog_position');
  except
    on E:exception do
      Logfile.Error('U_JsLogbook.AddParams: ' + E.Message);
  end;
end;

procedure TJsLogbook.AddValues;
begin
  inherited;
  try
    fQuery.ParamByName('fldlog_firstentry').AsBoolean              := fEntryFirst;
    fQuery.ParamByName('fldlog_application').AsString              := fEntryApplication;
    fQuery.ParamByName('fldlog_section').AsString                  := fEntrySection;
    fQuery.ParamByName('fldlog_position').AsString                  := fEntryPosition;
  except
    on E:exception do
      Logfile.Error('U_JsLogbook.AddValues: ' + E.Message);
  end;
end;

function TJsLogbook.Save: string;
begin
  try
    AddFields;
    AddParams;
    AddValues;
  except
    on E:exception do
      Logfile.Error('U_JsLogbook.Save: ' + E.Message);
  end;
end;

procedure TJsLogbook.Update;
var
  Query: TUniQuery;
  myYear, myMonth, myDay: Word;
  myHour, myMin, mySec, myMilli : Word;
  LogTime: TDate;
begin
  Query := frmUniConn.CreateQuery;
  try
    Query.SQL.Clear;
    Query.SQL.Add('UPDATE ' + TableLogbook);
    Query.SQL.Add('  SET fldlog_day = :fldlog_day');
    Query.SQL.Add('      ,fldlog_date = :fldlog_date');
    Query.SQL.Add('      ,fldlog_year = :fldlog_year');
    Query.SQL.Add('      ,fldlog_month = :fldlog_month');
    Query.SQL.Add('      ,fldlog_week = :fldlog_week');
    Query.SQL.Add('      ,fldlog_text = :fldlog_text');
    Query.SQL.Add('      ,fldlog_type = :fldlog_type');
    Query.SQL.Add('      ,fldlog_contact = :fldlog_contact');
    Query.SQL.Add('      ,fldlog_section = :fldlog_section');
    Query.SQL.Add('      ,fldlog_position = :fldlog_position');
    Query.SQL.Add('      ,fldupdated_computer = :fldupdated_computer');
    Query.SQL.Add('      ,fldupdated_by = :fldupdated_by');
    Query.SQL.Add('      ,fldupdated_date = :fldupdated_date');
    Query.SQL.Add(' WHERE (fldlog_application = :fldlog_application)');
    Query.SQL.Add('  AND (fldlog_firstentry = :fldlog_firstentry)');
    Query.ParamByName('fldlog_day').AsString                        := FormatSettings.ISOLongDayNames(DayOfTheWeek(EntryDate));
    Query.ParamByName('fldlog_date').AsDateTime                    := EntryDate;
    Query.ParamByName('fldlog_year').AsInteger                      := YearOf(EntryDate);
    Query.ParamByName('fldlog_month').AsInteger                    := MonthOf(EntryDate);
    Query.ParamByName('fldlog_week').AsInteger                      := WeekOf(EntryDate);
    Query.ParamByName('fldlog_text').AsString                      := EntryText;
    Query.ParamByName('fldlog_type').AsString                      := EntryType;
    Query.ParamByName('fldlog_contact').AsString                    := EntryContact;
    Query.ParamByName('fldlog_section').AsString                    := fEntrySection;
    Query.ParamByName('fldlog_position').AsString                  := fEntryPosition;
    Query.ParamByName('fldupdated_computer').AsString              := Network.ComputerName;
    Query.ParamByName('fldupdated_by').AsString                    := User.ID;

    Query.ParamByName('fldlog_application').AsString                := fEntryApplication;
    Query.ParamByName('fldlog_firstentry').AsBoolean                := True;

    LogTime := DateOf(EntryDate);
    DecodeDate(LogTime, myYear, myMonth, myDay);
    DecodeTime(Now, myHour, myMin, mySec, myMilli);
    LogTime := EncodeDateTime(myYear, myMonth, myDay, myHour, myMin, mySec, myMilli);
    Query.ParamByName('fldupdated_date').AsDateTime                := LogTime;
    try
      Query.Execute;
    except
      on E:exception do
        Logfile.Error('U_JsLogbook.Update: ' + E.Message);
    end;
  finally
    Query.Free;
  end;
end;

// Getters and setters
procedure TJsLogbook.SetPosition(const Value: string);
begin
  if Value = GuidEmpty then
    fEntryPosition := ''
  else
    fEntryPosition := Value;
end;

procedure TJsLogbook.SetSection(const Value: string);
begin
  if Value = GuidEmpty then
    fEntrySection := ''
  else
    fEntrySection := Value;
end;


end.

Dette kan kaldes sådan:

procedure TfrmMain.Button2Click(Sender: TObject);
var
  Logbook: TLogbook;
begin
  Logbook := TLogbook.Create;
  try
    Logbook.EntryDate    := Date;
    Logbook.EntryText    := 'Sendt email til en eller anden';
    Logbook.EntryType    := GuidLogbookMail;
    Logbook.EntryContact  := GuidEmpty;
    Logbook.Save;
  finally
    Logbook.Free;
  end;
end;

procedure TfrmMain.Button3Click(Sender: TObject);
var
  JsLogbook: TJsLogbook;
begin
  JsLogbook := TJsLogbook.Create;
  try
    JsLogbook.EntryDate        := Date;
    JsLogbook.EntryText        := 'Sendt email til en eller anden';
    JsLogbook.EntryType        := GuidLogbookMail;
    JsLogbook.EntryContact      := GuidEmpty;
    JsLogbook.EntryApplication  := GuidEmpty;
    JsLogbook.EntryPosition    := GuidLogbookMail;
    JsLogbook.EntrySection      := GuidLogbookMail;
    JsLogbook.Save;
  finally
    JsLogbook.Free;
  end;

end;
Avatar billede arne_v Ekspert
16. februar 2014 - 15:48 #7
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester