Laat ons een klein voorbeeldje bouwen ter illustratie, dan wordt alles wat minder theoretisch. Aan de hand van het voorbeeld kunnen we de zaak dan wat verder opbouwen.
Het voorbeeldje wordt opgebouwd aan de hand van:
1. Statisch
2. ADO ( omdat dit bijvoorbeeld ook werkt met Access )
3. Werkt zonder cache
4. Werkt zonder logs
5. Werkt met 'Save-At-Change'. Elke verandering wordt altijd ogenblikkelijk weggeschreven.
Al bij al technisch misschien niet de beste oplossing, maar wel de eenvoudigste om uit te leggen.
Voor deze gelegenheid heb ik een tabel gemaakt ( in een Access-databank ) met één tabel: tblKlant, dit met de velden:
IdNr, met autonummering
Naam, varchar(50),
VoorNaam, varchar(50),
Gemeente, varchar(50)
Dit voorbeeldje bestaat uit een 4-tal units:
1. Een form met een DbGrid, een TEdit en twee knoppen
2. Een datamodule met een ADO-Connectie
3. Een basis-Object met twee ADO Query's, voor de gelegenheid gebrouwd.
4. Het TKlant-object.
1. We starten met Datamodule met een ADO-Connectie.
2. We hebben een Basis-Object:
Dit object bevat ondermeer:
- Een Select-Query
- Een Update-Query
- De standaard-foutafhandeling.
Code:
unit UntDbCustom;
interface
uses DBTables, Classes, SysUtils, Variants, Dialogs,
Forms, Controls, UntDb, DB, ADODB;
type TDbCustom = class
private
FExist : boolean;
FFout : TString;
protected
FQueryUpdate : TADOQuery;
FQuerySelect : TADOQuery;
FIsDirty : boolean; // wordt gezet telkens geschreven wordt naar de databank
property QueryUpdate : TADOQuery read FQueryUpdate write FQueryUpdate;
property QuerySelect : TADOQuery read FQuerySelect write FQuerySelect;
property Fout: string read FFout write FFout;
procedure SetF(vVeld: String; vWaarde: Variant);
procedure SetFoutMessage(const Value: string); // Bestaat het object
procedure GetSQLSelect; virtual; abstract;
procedure GetSQLUpdate(vVeld : string); virtual;
function GetF(vVeld: String): Variant; virtual;
function GetFid (vVeld: String): Variant;
procedure SetEMessage(E: Exception);
destructor destroy; override;
public
property Exist: boolean read FExist;
property Data : TADOQuery read FQuerySelect;
constructor createNoFetch; virtual;
procedure Fetch;
end;
implementation
constructor TDbCustom.createNoFetch;
begin
inherited create;
FQuerySelect := TADOQuery.Create(nil);
FQuerySelect.Connection := Connections.ADOConnection;
FQueryUpdate := TADOQuery.Create(nil);
FQueryUpdate.Connection := Connections.ADOConnection;
FIsDirty := True;
FExist := false;
end;
procedure TDbCustom.Fetch;
begin
FIsDirty := False;
With QuerySelect do
begin
try
Close;
Sql.Text := '';
GetSQLSelect;
FExist := false;
Open;
FExist := true;
except
on E: Exception do SetEMessage(E);
end;
end;
end;
// De procedure SetEMessage wordt gebruikt om een fout te tonen op het scherm wanneer deze zich voordoet.
procedure TDbCustom.SetEMessage(E: Exception);
var i : byte;
EMessage: string;
begin
Fout:= E.Message;
FExist:= false;
end;
procedure TDbCustom.SetF (vVeld: String; vWaarde: Variant);
var lRetry : byte;
lOk : boolean;
begin
lRetry:=0;
If QuerySelect.Active
and (QuerySelect.FieldByName(vVeld).AsVariant = vWaarde)
then Exit;
FIsDirty := True;
if Exist then
With QueryUpdate do
begin
Close;
GetSQLUpdate(vVeld);
try
Parameters.ParamByName('Waarde').Value := vWaarde;
ExecSQL;
except
On E: Exception Do SetEMessage(E);
end;
end;
end;
function TDbCustom.GetFid (vVeld: String): Variant;
begin
if Exist
then
begin
try
with QuerySelect do
Result := FieldByName(vVeld).AsVariant;
except
on E: Exception do SetEMessage(E);
end;
end;
end;
function TDbCustom.GetF (vVeld: String): Variant;
begin
if Exist
then
begin
if FIsDirty then Fetch;
Result := GetFid(vVeld);
end;
end;
procedure TDbCustom.GetSQLUpdate(vVeld: string); begin end;
destructor TDbCustom.destroy;
begin
FreeAndNil(FQueryUpdate);
FreeAndNil(FQuerySelect);
inherited destroy;
end;
end.
Hiervan gaan we het ander object van afleiden: TKlant;
Behalve de Getters en de Setters hebben we hier twee speciale procedures die Tabel-afhankelijk zijn:
1. De "GetSQLSelect": Hierin wordt de Query geschreven om de select te doen
2. De "UpdateSelect": Hierin wordt de Update-Query geschreven.
Code:
unit UntKlant;
interface
uses UntDbCustom;
type TKlant= class(TdbCustom)
private
function GetGemeente: string;
function GetNaam: String;
function GetVoorNaam: String;
procedure SetGemeente(const Value: string);
procedure SetNaam(const Value: String);
procedure SetVoorNaam(const Value: String);
protected
procedure GetSQLSelect; override;
procedure GetSQLUpdate(vVeld : string); override;
public
property Naam: String read GetNaam write SetNaam;
property VoorNaam: String read GetVoorNaam write SetVoorNaam;
property Gemeente: string read GetGemeente write SetGemeente;
end;
implementation
{ TKlant }
function TKlant.GetGemeente: string;
begin
Result:= GetF('Gemeente');
end;
function TKlant.GetNaam: String;
begin
Result:= GetF('Naam');
end;
function TKlant.GetVoorNaam: String;
begin
Result:= GetF('VoorNaam');
end;
procedure TKlant.GetSQLSelect;
begin
With QuerySelect do
SQL.Text:= 'SELECT * FROM TblKlant';
end;
procedure TKlant.GetSQLUpdate(vVeld: string);
begin
With QueryUpdate do
begin
SQL.Text:= 'UPDATE TblKlant SET ' + vVeld + '= :Waarde WHERE IdNr = :Idnr';
Parameters.ParamByName('IdNr').Value:= GetFId('IdNr');
end;
end;
procedure TKlant.SetGemeente(const Value: string);
begin
SetF('Gemeente', Value);
end;
procedure TKlant.SetNaam(const Value: String);
begin
SetF('Naam', Value);
end;
procedure TKlant.SetVoorNaam(const Value: String);
begin
SetF('VoorNaam', Value);
end;
end.
en ten slotte de form:
De form bestaat uit een aantal componenten:
1. Een DbGrid met daaraan een Datasource gekoppeld: DtsKlant
2. Een gewone TEdit. Hier heb ik nu de onDataChange-event gebruikt om hem op te vullen.
3. Een knop om een refresh te doen ( Fetch )
4. Een knop om de TEdit weg te schrijven.
Er bestaan heel wat betere methodes om dit te doen, maar daar kom ik later wel op terug.
Code:
type
TForm1 = class(TForm)
ADOQuery1: TADOQuery;
DBGrid1: TDBGrid;
DtsKlant: TDataSource;
BtnOphalen: TButton;
EdtKlant: TEdit;
BtnOpslaan: TButton;
Label1: TLabel;
procedure BtnOphalenClick(Sender: TObject);
procedure DtsKlantDataChange(Sender: TObject; Field: TField);
procedure BtnOpslaanClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
FKlant: TKlant;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.BtnOphalenClick(Sender: TObject);
begin
FKlant.Fetch;
end;
procedure TForm1.DtsKlantDataChange(Sender: TObject; Field: TField);
begin
Edit1.Text:= FKlant.Naam;
end;
procedure TForm1.BtnOpslaanClick(Sender: TObject);
begin
FKlant.Naam:= Edit1.Text;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FKlant:= TKlant.CreateNoFetch;
DtsKlant.Dataset:= FKlant.Data;
end;
Ik zou zeggen, probeer het voorbeeldje eens uit. Als dit voor iedereen duidelijk is, gaan we een stap verder.
Bookmarks