• ThreeTierDatenbankanwendung mit ADO


    Three-Tier-Datenbankanwendung mit ADO

    Frage: Wie kann ich eine Three-Tier-Datenbankanwendung, die mit ADO auf die Datenbank zugreift, ohne TClientDataset umsetzen?

    Antwort: Das folgende Beispiel für eine Three-Tier-Datenbankanwendung nutzt COM+ auf der Server-Seite, um ein mit Daten gefülltes Recordset-Objekt (ADO) an den Client zurückzuliefern (Interface-Methode GetRS) beziehungsweise dessen Änderungen wieder in der Datenbank einzuarbeiten (Interface-Methode UpdRS).

    Implementierung im COM+ Objekt (Server)

    Das COM+-Objekt erzeugt das mit den Datensätzen der Ergebnismenge der SELECT-Abfrage gefüllte Recordset, und liefert dieses über den Interface-Zeiger _Recordset an den Client zurück. Damit das Recordset diesen Transport "überlebt", muss vorher die Datenbankverbindung zwischen Recordset und Datenbank gekappt werden (Methode Set_ActiveConnection). In der Gegenrichtung sorgt der Server dafür, dass das vom Client als Interface-Zeiger übergebene Recordset mit den vom Anwender geänderten Daten vor dem Aufruf der Methode UpdateBatch kurzzeitig wieder mit der Datenbank verbunden wird. Da ADO über die Fähigkeiten von OLE DB automatisch einen Datenbankverbindungs-Pool nutzt, führt dieses ständige Verbinden und Trennen zu keiner Verzögerung, da sofort eine freie Datenbankverbindung aus dem Pool zugeordnet wird und der Pool zur Laufzeit dynamisch wächst, wenn es notwendig wird.

    unit UpdBatch_Impl;
    { SYMBOL_PLATFORM OFF}
    
    interface
    uses ActiveX, Mtsobj, Mtx, ComObj, UpdBatch_Impl_TLB, StdVcl, ADODB_TLB;
    type TUpdBatchObj = class(TMtsAutoObject, IUpdBatchObj) protected procedure UpdRS(const aRS: _Recordset; out sSrvMsg: WideString); safecall; procedure GetRS(out aRS: _Recordset; out sSrvMsg: WideString); safecall; { Protected-Deklarationen } end;
    implementation
    uses ComServ, Variants;
    resourcestring cCS = 'Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;' + 'Initial Catalog=tempdb;Data Source=(local)';
    procedure TUpdBatchObj.GetRS(out aRS: _Recordset; out sSrvMsg: WideString); var aCon : _Connection; aRSTmp: _Recordset; begin aCon := CoConnection.Create as _Connection; aCon.CursorLocation := adUseClient; aCon.Open(cCS, '', '', adConnectUnspecified); try aRSTmp := CoRecordSet.Create as _Recordset; aRSTmp.CursorLocation := adUseClient; aRSTmp.Open('select PK, Wert1, Wert2 from UpdateBatchNOTNULL', aCon, adOpenStatic, adLockBatchOptimistic, adCmdText); aRS := aRSTmp; aRS._Set_ActiveConnection(nil); finally aCon.Close; end; sSrvMsg := 'ok'; SetComplete; end;
    procedure TUpdBatchObj.UpdRS(const aRS: _Recordset; out sSrvMsg: WideString); var aCon : _Connection; begin aCon := CoConnection.Create as _Connection; aCon.CursorLocation := adUseClient; aCon.Open(cCS, '', '', adConnectUnspecified); aRS.Set_ActiveConnection(aCon); aRS.UpdateBatch(adAffectAll); aRS._Set_ActiveConnection(nil); aCon.Close; aCon := nil; sSrvMsg := 'ok'; SetComplete; end;
    initialization TAutoObjectFactory.Create(ComServer, TUpdBatchObj, Class_UpdBatchObj, ciMultiInstance, tmApartment); end.
    Implementierung im Client

    Der Client hat keine Verbindung zur Datenbank, er kennt noch nicht einmal die Datenbank, von der die Daten stammen. Statt dessen erhält der Client vom COM+-Objekt des Servers nur das bereits mit den Datensätzen der Ergebnismenge gefüllte Recordset, um dieses einer TADODataSet-Komponente unterzuschieben. Diese TADODataSet-Komponente wird im Objektinspektor nicht konfiguriert, sondern die Komponeten übernimmt die Daten direkt vom bereits gefüllten Recordset-Objekt. TADODataSet dient nur dazu, über TDataSource ein TDBGrid zur Bearbeitung der Datenmenge nutzen zu können. Um die vom Anwender vorgenommenen Änderungen an den Datensätzen in die Datenbank einzuspielen, ruft der Client die Interface-Methode UpdRS des COM+-Objekts auf, um dabei das gefüllte Recordset in Form des Interface-Zeigers als Parameter zu übergeben. Zusätzlich kann der Client festlegen, dass dabei nur die vom Anwender geänderten Datensätze zum Server transportiert werden sollen.
    unit CltUpdateBatchFrm;
    
    interface
    uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DB, ADODB, ExtCtrls, DBCtrls, Grids, DBGrids, StdCtrls, UpdBatch_Impl_TLB, ComCtrls;
    type TForm1 = class(TForm) Button1: TButton; DBGrid1: TDBGrid; DBNavigator1: TDBNavigator; ADODataSet1: TADODataSet; DataSource1: TDataSource; StatusBar1: TStatusBar; Button2: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private-Deklarationen } FSrv : IUpdBatchObj; public { Public-Deklarationen } end;
    var Form1: TForm1;
    implementation
    { *.dfm}
    uses ADODB_TLB, ADOInt;
    procedure TForm1.FormCreate(Sender: TObject); begin FSrv := CoUpdBatchObj.CreateRemote('192.168.10.1'); end;
    procedure TForm1.Button1Click(Sender: TObject); var aRS : ADODB_TLB._Recordset; swSrvMsg : WideString; begin FSrv.GetRS(aRS, swSrvMsg); ADODataSet1.Recordset := ADOInt._Recordset(aRS); ADODataSet1.Active := True; StatusBar1.SimpleText := swSrvMsg; end;
    procedure TForm1.Button2Click(Sender: TObject); var aRS : ADODB_TLB._Recordset; swSrvMsg : WideString; begin aRS := ADODB_TLB._Recordset(ADODataSet1.Recordset); FSrv.UpdRS(aRs, swSrvMsg); StatusBar1.SimpleText := swSrvMsg; end;
    procedure TForm1.ADODataSet1NewRecord(DataSet: TDataSet); begin ADODataSet1.FieldByName('Wert2').Value := ''; end;
    end.
    Die ganzen Hintergründe dazu sind in den folgenden Büchern zu finden:
    a) http://www.software-support.biz/sus/sus_buch/psecom,id,4,nodeid,11,_language,de.html
    b) http://www.software-support.biz/sus/sus_buch/psecom,id,21,nodeid,11,_language,de.html


  • 相关阅读:
    IO流
    myEclipse的使用
    单例模式
    日期的使用
    String类的常用方法
    break、continue和return的区别
    包装类和随机数
    enum类的使用
    Java基础概念性的知识总结
    汇编中的函数调用与递归
  • 原文地址:https://www.cnblogs.com/fuyingke/p/254659.html
Copyright © 2020-2023  润新知