Page 2 of 10 FirstFirst 1 2 3 4 ... LastLast
Results 16 to 30 of 144

Thread: Business Objects - het begin.

  1. #16
    De principes hierboven uitgelegd zijn de basis van een aantal systemen die ongeveer volgens hetzelfde principe werken, maar de gebruikte techniek kan verschillen en het ene is meer geavanceerd dan het andere, maar meestal omvatten ze wel de volgende onderdelen:
    1. Een knowledge-base ( van welke vorm dan ook, bv. UML ) waar de structuren onafhankelijk van enig systeem worden opgeslagen.
    2. Een Database-generator: deze maakt de tabellen ( en andere Db-objecten ) vanuit de knowledge-base.
    3. Een code ( of framework ) generator die de code of het framework aanmaakt.

    OPF is in deze contreien waarschijnlijk het bekendst, maar daarnaast zijn er nog een aantal andere zoals BOLD, IO, ECO, AOL, ... en nog een aantal andere met een drieletterwoord. De meeste zijn commercieel maar, zoals Marcov al vertelde, kun je dit ook zelf bouwen. Ik zal in een volgende tread misschien een voorbeeld geven hoe je dit kunt doen.

    Een onderscheid kan gemaakt worden tussen de systemen die dynamische link hebben ( werken via een structuur in de database of systemen als RTTI ), terwijl de andere een statische link hebben ( hierbij worden de structuren eerst omgezet in code en daarna gecompileerd ). Elk van die systemen heeft zo zijn voor- en nadelen.
    Last edited by rik.osstyn; 26-Nov-07 at 00:55.
    De verbazing begint waar de kennis ophoudt

  2. #17
    Counting your refs Paul-Jan's Avatar
    Join Date
    Feb 2002
    Location
    Lage Zwaluwe
    Posts
    2,160
    Ter aanvulling:
    - In sommige systemen zijn 1 & 3 verweven (kennis zit in meta-comments boven de code, dataobjects.net et al)
    - Generatie van 3 uit 2 zonder afzonderlijke 1 komt toch ook voor? Ik ben niet zo'n kenner, maar staat me bij dit nog wel eens voorbij te hebben zien komen.
    - Ons eigen framework, en anderen vast ook, gebruikt zowel de genoemde "dynamische" als "statische" link. De daadwerkelijke onderliggende communicatie-laag maakt gebruik van @runtime gevulde containers, maar daar kun je voor convenience ook via gegenereerde properties/methods bij als ontwikkelaar.

  3. #18
    Hoi Allen,

    Dit is toch wel echt interessante materie.

    Hebben jullie misschien een link naar een goed boek of online artikel.

    Alvast bedankt.

  4. #19
    senior member PeterVercruysse's Avatar
    Join Date
    Nov 2006
    Location
    Rijsel
    Posts
    1,608
    Er bestaan wel heel wat artikels over dit onderwerp, maar de meeste zijn nogal moeilijk begrijpbaar.

    - Generatie van 3 uit 2 zonder afzonderlijke 1 komt toch ook voor? Ik ben niet zo'n kenner, maar staat me bij dit nog wel eens voorbij te hebben zien komen.
    Dit bestaat zeker ook. Hierbij wordt de masterdata van de ( meestal bestaande ) databank gebruikt om het framework op te bouwen.

    Ons eigen framework, en anderen vast ook, gebruikt zowel de genoemde "dynamische" als "statische" link.
    Ik denk dat iedereen dit wel doet. Statische links worden eerder gebruikt om Business Rules te programmeren.

    Dynamische eerder links voor de GUI. Hier vind je normaal ook de software terug die bijvoorbeeld zorgt voor een dynamische schermopbouw.
    Gras groeit niet sneller door er aan te trekken

  5. #20
    Delphi & OO in Vlaanderen SamWitse's Avatar
    Join Date
    Sep 2007
    Location
    Brussel
    Posts
    833
    Peter,

    Heb jij enige leesbare tekst, voor hobbyisten, en natuurlijk in Delphi?

    Ik heb zelf ooit descendants van TTable gemaakt, waarbij de properties als TFields gebruikt konden worden in standaard data-aware componenten zoals TDBEdits, TDBGrids.
    Ik was echter niet helemaal tevreden over het resultaat, wellicht omdat ik geen weet had over bestaande practices.
    Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought, proper consideration.

    Sam Witse.
    Delphi & OO in Vlaanderen

  6. #21
    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.
    Attached Files Attached Files
    Last edited by rik.osstyn; 27-Nov-07 at 22:16.
    De verbazing begint waar de kennis ophoudt

  7. #22
    senior member PeterVercruysse's Avatar
    Join Date
    Nov 2006
    Location
    Rijsel
    Posts
    1,608
    Heb jij enige leesbare tekst, voor hobbyisten, en natuurlijk in Delphi?
    Ik zal dit eens nazien.
    Gras groeit niet sneller door er aan te trekken

  8. #23
    senior member PeterVercruysse's Avatar
    Join Date
    Nov 2006
    Location
    Rijsel
    Posts
    1,608
    Je zult namelijk je eigen TField-afgeleiden moeten maken.
    Waarom zou je dit doen?
    Gras groeit niet sneller door er aan te trekken

  9. #24
    Ik heb normaal geen code in de getters ( de mapping gebeurt vooraf ), dan zijn de gegevens uit de databank identiek aan deze in je objecten. Dit betekent dat je om de lezen enkelzijdige Db-Aware componenten kunt gebruiken.
    Een TDbEdit heeft een dubbelzijdige koppeling: de gegevens worden automatisch uit een dataset gelezen en bij verandering er terug in gelezen. Er bestaan ook enkelzijdige componenten die de datasource volgen bij elke verandering, zoals een TdbEdit dit zou doen, maar die geen koppeling heeft om te schrijven. Op dat gebied gedraagt het component zich als een gewone TEdit, wat ook nodig is, want elke geschreven waarde moet gevalideerd worden door het framework.

    Het grote voordeel van deze methode ( voor manueel ontwerpen schermen dan ), is dat je de schermopbouw volgens exact dezelfde manier kunt opbouwen als je met Db-Componenten doet. Het grote verschil zit hem in het opslaan van de gegevens. Daar waar bij de klassieke methode alles wordt geverifieerd in een event ( bijvoorbeeld een BeforePost ), worden de gegevens doorgegeven aan de objecten, en indoen goedgekeurd, worden deze opgeslagen.

    Het opslaan van data kan gebeuren in een aantal modi, met ook telkens de mogelijkheid van triggering e.d. . Ik onderscheid de volgende gevallen:
    1. Veld per Veld: telkens een property wordt aangepast, wordt dit weggeschreven naar de databank. Vooral voor produktietoepassingen
    2. Record per record: dit is de klassieke manier. De velden worden aangepast en weggeschreven na een commando ( Post ).
    3. Meerdere Records: Verschillende records worden bijgehouden en in één keer weggeschreven. Dit kan in combinatie met Batch-verwerking als de server dit ondersteund.

    Deze mogelijkheden kunnen dan nog gecombineerd worden met transacties, én met de mogelijkheid om 'dirty-writes' te gaan vermijden, dit is de mogelijkheid om niet weg te schrijven indien de gegevens ondertussen al gewijzigd zijn.

    In het voorbeeld is enkel 1. van toepassing, omdat dit het eenvoudigste is, de rest kan ook perfect.

    Hier bijgevoegd, een voorbeeld van een dergelijk component ( UntEdits.pas ), samen met een projectvoorbeeld.
    Attached Files Attached Files
    Last edited by rik.osstyn; 28-Nov-07 at 01:28.
    De verbazing begint waar de kennis ophoudt

  10. #25
    senior member PeterVercruysse's Avatar
    Join Date
    Nov 2006
    Location
    Rijsel
    Posts
    1,608
    Heb jij enige leesbare tekst, voor hobbyisten, en natuurlijk in Delphi?
    Ondertussen heb ik er een gevonden, maar hij is een beetje te groot om op het forum te plaatsen. Stuur maar een PM.
    Gras groeit niet sneller door er aan te trekken

  11. #26
    Docjes, txttjes, pdfjes en zipjes mogen geloof ik 100 Kb zijn. Is er geen vorm waarin je het kan posten? Het is wellicht ook leerzaam voor andere leden.
    1+1=b

  12. #27
    senior member PeterVercruysse's Avatar
    Join Date
    Nov 2006
    Location
    Rijsel
    Posts
    1,608
    Je hebt wel gelijk GolezTrol, ik zoek een oplossing in die richting.
    Gras groeit niet sneller door er aan te trekken

  13. #28
    Je mag het ook aan mij mailen (marcel@...), dan zet ik het hier op de server.
    Marcel

  14. #29
    senior member PeterVercruysse's Avatar
    Join Date
    Nov 2006
    Location
    Rijsel
    Posts
    1,608
    Ik heb ( het begin van ) mijn documentatie wat opgeruimd en in twee delen gesplitst, dan lukt het net. Ingesloten zijn ook nog een aantal voorbeeldjes.
    Attached Files Attached Files
    Last edited by PeterVercruysse; 29-Nov-07 at 23:46.
    Gras groeit niet sneller door er aan te trekken

  15. #30
    senior member PeterVercruysse's Avatar
    Join Date
    Nov 2006
    Location
    Rijsel
    Posts
    1,608
    Dit moet er ook nog bij. Deze componentjes zijn nodig voor de goede werking. Ze moeten als component geïnstalleerd worden om de voorbeelden goed te laten functioneren.
    Attached Files Attached Files
    Last edited by PeterVercruysse; 29-Nov-07 at 23:47.
    Gras groeit niet sneller door er aan te trekken

Page 2 of 10 FirstFirst 1 2 3 4 ... LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •