Home

Delphi - Database application tutorial (slot)

1. Inleiding

In de voorgaande papers van deze database-basics turorial hebben we vooral naar de theorie gekeken.
In dit slot paper gaan we een eenvoudige database applicatie schrijven.
De applicatie toont de hiervoor besproken technieken. Het is geen compleet afgewerkte applicatie, daar het
alleen de bedoeling is om de technieken te tonen.

DownloadDownload hier de source

2. De database tabellen

Het doel van de applicatie is om projecten te beheren. Bij deze projecten kunnen de tekeningen toegevoegd worden.
De gehele applicatie bestaat uit drie tabellen te weten :

Het betreft hier Paradox tabellen, met de volgende structuur :
* = Index van de tabel, A = Alpha numeriek (karakter) D=Datumveld.

Project.db
FieldName Type Size Key
Projectnr A 6 *
Description A 50  
ClientCode A 6  
Date D    
Drawing.db
FieldName Type Size Key
Drawingnr A 11 *
Description A 50  
Drawnby A 10  
Date D    
DrawProject.db
FieldName Type Size Key
Drawingnr A 11 *
Projectnr A 6 *
Secondary indexes :
OnDrawingnr  : Field Drawingnr
OnProjectnr : Field Projectnr

De tabellen Project en drawing zijn middels een meer-op-meer relatie aan elkaar verbonden.
Het komt er opneer dat een tekening tot meerdere projecten kan toehoren, en dat een project meer tekeningen kan hebben.
De relatie wordt in de tabel DrawProject vastgelegd.

3. De Applicatie

De applicatie voorziet in één mainform waarop een tab-control is geplaatst met drie tabsheets.
Het eerste tabsheet toont de projecten. Hier kunnen :

Het tweede tabsheet toont een browse overzicht van alle tekeningen, hier kunnen tekeningen toegevoegd, verwijdert en gewijzigd worden.
Het derde tabsheet biedt de mogelijkheid om SQL commando's in te voeren en te executen.
Zoals gezegd geen complete applicatie, maar wel één met alle database technieken in zich.

De volgende Forms behoren tot het project :

frmMain - het hoofdform
dmProject - een datamodule die de databasecomponenten bevat.
frmAddItem - een 'algemeen' form die met behulp van een klasse tekeningen toe voegt aan een project. (Hierover later meer)
modBrowse - een unit, geen form, die een klasse definitie voor het toevoegen van de tekeningen verzorgt.

3.1 Het instellen van de database componenten

Als eerste dient er middels de BDE-Administrator een database alias gemaakt te worden, met de volgende instellingen :

bdeadmin.jpg (21201 bytes)

De alias heet Project en verwijst naar een fysieke lokatie op schijf. (Vul bij path de directory in)
Nu dit gedaan is kunnen we de database componenten in de datamodule dmProject plaatsen en instellen.
Wat hebben we nodig :

dmProject.jpg (27405 bytes)

Hierboven staat een screendump van de datamodule dmProject. De instellingen per component :

Het instellen van de properties van de data-access componenten :

tbProject   Query  
DataBasename Project DataBaseName Project
Name tbProject Name Query
TableName Project.db    
tbProject is voor het managen van de projectgegevens. Query is het component waarmee alle TTables geraadpleegt kunnen worden middels SQL
dsProject   dsQuery  
DataSet tbProject Dataset Query
Name dsProject Name dsQuery
dsProject is de datasource behorende bij tbProject. dsQuery is de datasource behorende bij Query.
tbDrawing   dsDrawingToProject  
DataBaseName Project Dataset tbDrawingToProject
Name tbDrawing Name dsDrawingToProject
TableName Drawing.db    
tbDrawing is voor het managen van de tekeninggegevens. dsDrawingToProject is de datasource behorende bij tbDrawingToProject.
tbPrjDwg   tbDrawingToProject  
DataBaseName Project DataBaseName Project
Name tbPrjDwg Name tbDrawingToProject
TableName DrawProject.db TableName Drawing.db
MasterSource dsProject MasterSource dsPrjDwg
MasterFields Projectnr. MasterFields Drawingnr
IndexName OnProjectnr    
tbPrjDwg toont de tekeningen die bij het huidige project horen. Ofwel de mastersource is dsProject, zodat tbPrjDwg een resultset toont van alleen die tekening uit tabel drawproject.db die als projectnr. het huidige projectnr, uit tbProject hebben. Merk op dat de IndexName wijst naar de secondary index OnProjectnr. tbDrawingToProject toont de tekeninggegevens van de huidige tekening in tbPrjDwg. De mastersource is dsPrjDwg. Deze TTable toont altijd maar één record, namelijk op basis van het huidige tekeningnr in tbPrjDwg.
dsPrjDwg      
DataSet tbPrjDwg    
Name dsPrjDwg    
dsPrjDwg is de datasource behorende bij tbPrjDwg.    

 

De dataware componenten van het programma moeten als volgt ingesteld worden :

databaseapp.jpg (67568 bytes)

Onder de tab Drawings bevindt zich een DBGrid waar de tekeningen in beheerd worden, deze heeft als datasource dsDrawing.

3.2 Het toevoegen van tekeningen aan een project

Middels de knop Add a drawing to this project kunnen tekeningen toegevoegd worden aan het huidige project.
Er wordt een tekening gekozen uit de tabel Drawing, deze wordt in combinatie met het project nummer toegevoegd in de tabel tbPrjDwg.
Om de tekening te kiezen moet een apart form gemaakt worden waarin alle tekeningen getoond worden.
Dit form zouden we natuurlijk kunnen bouwen op de manier zoals hierboven door handig om te gaan met de datasources en componenten.
Voor dit demoprogramma zou dit goed werken. Echter in een echte applicatie zou je misschien ook projecten willen toevoegen aan tekeningen, of
willen tooevoegen aan 'wat dan ook'.
Het is dus zaak het 'toevoeg' form zo abstract mogelijk te houden, zodat het voor allerlei toevoeg acties hergebruikt kan worden.
Hoe zou dit gerealiseerd kunnen worden :

  1. Door de componenten vanuit de aanroepende code in te stellen, voordat het form opkomt.
  2. Door properties op het toevoegform in te stellen, waarna het form zich zelf kan instellen.
  3. Door een class te bouwen waarmee op gemakkelijke wijze alle properties kunnen worden ingesteld, en
    waar in de toekomst makkelijk items toegevoegd kunnen worden zonder de daadwerkelijke programmacode te moeten wijzigen.

De punten 1 en 2 kunnen op zich best voldoen, maar brengen veel (dezelfde) code in ons programma waar we ons eigenlijk niet mee bezig willen houden.
Verder hebben zij als nadeel dat als er onverhoopt een wijziging plaatsvindt die onherroepelijk op meerdere plaatsen in de code zal moeten worden doorgevoerd.
Uit OOP oogpunt is optie 3 de beste oplossing, deze hebben we in deze applicatie dan ook toegepast.

Het toevoegscherm :

frmadd.jpg (8743 bytes) Het toevoegscherm is heel eenvoudig, en bestaat uit een DBGrid en twee buttons.
Er worden tijdens het ontwerp geen database properties geset. We willen immers dit
scherm voor meerdere tabellen gebruiken.

 

De volgende class verzorgt de instellingen van het toevoegscherm : (modBrowse.pas)

/////////////////////////////////////////////////////////////////////////////
// modBrowse class
// Used for setting the frmAddItem form
//
// (c) beensoft@yahoo.com    http://surf.to/beensoft
////////////////////////////////////////////////////////////////////////////


unit modBrowse;

interface

uses DB, Classes;

resourcestring
  SAddDWG = 'Add a drawing';


type
  TDBBrowseClass = class
  private
    { Private declarations }
    FDataSource : TDataSource;
    FFieldCaptionList : TStrings;
    FFieldList : TStrings;
  public
    { Public declarations }
    Constructor CreateBrowse (aDataSource : TDataSource);
    Destructor Destroy; Override;
    function GetCaption : string; virtual; abstract;
    function GetFieldCaptionList : TStrings; virtual;
    function GetFieldList : TStrings; virtual;
    property Datasource : TDataSource read FDataSource write FDatasource;
    property FieldCaptionList : TStrings read FFieldCaptionList write FFieldCaptionList;
    property FieldList : TStrings read FFieldList write FFieldList;
  end;


//TDBDWGBrowse : Adding drawings
type
  TDBDWGBrowse = class(TDBBrowseClass)
  private
    { Private declarations }

  public
    { Public declarations }
    function GetCaption : string; override;
    function GetFieldCaptionList : TStrings; override;
    function GetFieldList : TStrings; override;
  end;

// Here you could create the TDBPrjBrowse for adding projects

implementation

{ TDBBrowse }

constructor TDBBrowseClass.CreateBrowse(aDataSource: TDataSource);
begin
  Inherited Create;
  FDataSource := aDataSource;              // the datasource
  FFieldCaptionList := TStringList.Create; // the collumncaptions of the grid
  FFieldList := TStringList.Create;        // the fields in the grid
end;


Destructor TDBBrowseClass.Destroy;
begin
  FFieldCaptionList.Free;   // free the caption stringlist
  FFieldList.Free;          // free the field list
  Inherited Destroy;
end;


function TDBBrowseClass.GetFieldCaptionList : TStrings;
begin
  FFieldCaptionList.Clear;    // clear the list (should be clear)
  Result := FFieldCaptionList;
end;

function TDBBrowseClass.GetFieldList : TStrings;
begin
  FFieldList.Clear;           // clear the list (should be clear)
  Result := FFieldList;
end;


{ TDBDWGBrowse }

function TDBDWGBrowse.GetCaption: string;
begin
  Result := SAddDWG;          //set the caption for DWG adding
end;

// For the captions of the grid columns
function TDBDWGBrowse.GetFieldCaptionList : TStrings;
begin
  FFieldCaptionList.Add('Drawingnr');
  FFieldCaptionList.Add('Description');
  result := FFieldCaptionList;
end;

// The FieldName list
function TDBDWGBrowse.GeTFieldList : TStrings;

begin
  FFieldList.Add('DRAWINGNR');
  FFieldList.Add('DESCRIPTION');
  result := FFieldList;
end;

end.

De main class wordt alleen gebruikt om de class te initialiseren (datasource) en om de stringlists te creëen en op te ruimen.
De virtual gedeclareerde methods kunnen in the subclass override worden met de specifieke wensen, zoals te gebruiken velden in de grid en captions.

Zoals deze class gebruikt wordt is nog steeds vrij statisch, je zou immers ook de te gebruiken velden via de aanroep kunnen initialiseren.
Indien dit wenselijk is zou je er bijna een component van kunnen maken waarin via properties alles ingesteld kan worden.
Dit is een goed idee voor het volgende te bouwen component !, het TDBBrowse component.

De aanroep vanuit ons programma gaat als volgt : (frmMain)

procedure TfrmMain.SetGridProps; // method can be used generally 
var I : Integer;                 // Browse : TDBBrowse 

begin
  frmAddItem.DBGridItems.Columns.Clear;              // Clear the 'normal'fieldlist
  For I := 0 to Browse.GetFieldList.Count - 1 do  // Add field and caption to DBGrid
  with frmAddItem do
  begin
    DBGridItems.Columns.Add;
    DBGridItems.Columns[I].FieldName := Browse.GetFieldList.Strings[I];
    DBGridItems.Columns[I].Title.Caption := Browse.GetFieldCaptionList.Strings[I];
  end;
end;


procedure TfrmMain.btnAddDWGClick(Sender: TObject); // Add a drawing button click

begin
  // First create the DWGBrowse object 
  Browse := TDBDWGBrowse.CreateBrowse(dmProject.dsDrawing);
  Try
    frmAddItem := TFrmAddItem.Create(self); // Create the form
    With frmAddItem do
    begin
      Caption := DWGBrowse.GetCaption;      // Set the caption of the form
      DBGridItems.DataSource := Browse.DataSource; // Parse the datasource to grid
      SetGridProps;        // Set grid properties method
      ShowModal;           // show the form
      With dmProject do    // Insert the drawing/project in tabel tbPrjDwg
      begin
        tbPrjDwg.Insert;
        tbPrjDwg.FieldByName('DRAWINGNR').AsString := tbDrawing.FieldByName('DRAWINGNR').AsString;
        tbPrjDwg.FieldByName('PROJECTNR').AsString := tbProject.FieldByName('PROJECTNR').AsString;
        tbPrjDwg.Post;
      end;
    end;
  Finally
    frmAddItem.Free;    // free the form
    Browse.Free;        // free the object
  end;
end;

 

3.3 Het maken van een query

Op het derde tabsheet van de tabcontrol kunnen we in een memo component SQL commando's invoeren. Die middels de button Execute query
uitgevoerd kan worden. De buttonclick event ziet er alsvolgt uit :

procedure TfrmMain.btnExecuteSQLClick(Sender: TObject);
begin
  with dmProject do
  begin
    Query.Close;
    Query.SQL.Clear;
    Query.SQL := mmSQL.Lines; // assign memolines to SQL
    Query.Open;
  end;
end;

Het resultaat van de querie, de resultset, wordt getoond in de DBGrid.

Middels deze demo-applicatie hebben wij getracht enkele delphi-database technieken duidelijk te maken.
Hiermee is de Tutorial Delphi basic-databasetechnieken compleet.

arrows.gif (215 bytes)Top