DELPHI與.Net

程序開發中......... [注明:该Blog中的信息都并非原创,只是作为个人的阅读笔记]

Three-Tier-Datenbankanwendung 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


posted on 2005-10-14 11:16  人淡如菊  阅读(374)  评论(0编辑  收藏  举报

导航