|
1. DATASNAP 歷史
作為MIDAS起始于Delphi3,Delphi4是MIDAS II,Delphi5中是MIDASIII,而后基于COM遠(yuǎn)程數(shù)據(jù)模塊方式使 Delphi2010中構(gòu)建于D2009架構(gòu)之上,并對(duì)此架構(gòu)做了進(jìn)一步的擴(kuò)展,包括使用兩個(gè)向?qū)韯?chuàng)建新的 1.1 DATASNAP范例數(shù)據(jù)位置 本白頁中我建議您使用Demo和范例來學(xué)習(xí).雖然Delphi支持很多數(shù)據(jù)庫系統(tǒng),使用DBX4,ADO dbGo,或 2. DATASNAP目標(biāo):如何獲取數(shù)據(jù) DataSnap2010支持三種不同的Windows方式:VCL窗體,Windows服務(wù)和控制臺(tái)應(yīng)用程序.本節(jié)中我們 下面會(huì)創(chuàng)建一個(gè)DataSnap服務(wù)端和客戶端,我們將講解 將討論不同的傳輸協(xié)議(TCP,HTTP)的好處及傳輸效率.并討論DataSnap服務(wù)對(duì)象的不同生命期選項(xiàng) 2.1. DATASNAP 服務(wù)端范例 在Object Repository中有兩個(gè)不同的DataSnap服務(wù)向?qū)?一個(gè)是生成基于Windows的Datasnap服務(wù) 啟動(dòng)了Delphi2010,點(diǎn)擊File.New.Other,你會(huì)在Object Repository中看到DataSnap服務(wù)向?qū)е?BR>顯示的三個(gè)圖標(biāo):DataSnap Server,DataSnap WebBroker Server,和Server Module. 雙擊第一個(gè)(后面的兩個(gè)在下面的小結(jié)中講解),彈出如下對(duì)話框: 界面中第一部分是控制項(xiàng)目類型的.默認(rèn)可以生成可視化的帶有主窗體的VCL窗體應(yīng)用程序.第二個(gè)
第二部分是選擇使用的Datasnap服務(wù)的通訊協(xié)議.和DanaSnap2009相比,我們可以看到多了一個(gè) 第三部分已經(jīng)為我們配置好了,如果我們要提供一個(gè)服務(wù)方法類,我們可以選擇它的基 現(xiàn)在是從DSServer.pas中貼出來的一小段代碼,來說明TDSServerModule和 TDSServerModuleBase = class(TProviderDataModule) public procedure BeforeDestruction; override; destructor Destroy; override; end; {$MethodInfo ON} TDSServerModule = class(TDSServerModuleBase) end; {$MethodInfo OFF} 當(dāng)無法確定時(shí)就使用TDSServerModule選項(xiàng)作為基類. 2.1.1. 創(chuàng)建多目標(biāo)項(xiàng)目組-- VCL 窗體項(xiàng)目 如上面所說,這里創(chuàng)建多目標(biāo)的Datasnap服務(wù)項(xiàng)目組.首先創(chuàng)建一個(gè)VCL窗體應(yīng)用程序作為Datasnap 默認(rèn)創(chuàng)建了一個(gè)叫做Project1.dproj的項(xiàng)目,并帶有三個(gè)單元文 稍后我們將向項(xiàng)目組添加控制臺(tái)應(yīng)用程序和Window服務(wù)應(yīng)用程序.首先我們來檢查一下項(xiàng)目,并編 ServerContainerUnitDemo的引用部分應(yīng)該向下面代碼所示: implementation uses Windows, ServerMethodsUnitDemo; {$R *.dfm} procedure TServerContainer1.DSServerClass1GetClass( DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); begin PersistentClass := ServerMethodsUnitDemo.TServerMethods1; end; end. 2.1.1.1. SERVERCONTAINERUNITDEMO 打開ServerContainerUnitDemo單元,將會(huì)看到不少于五個(gè)組件:一個(gè)TDSServer,一個(gè) 前面兩個(gè)一直會(huì)存在,其他的三個(gè)則是根據(jù)選擇的通訊協(xié)議生成的. 2.1.1.1.1. TDSSERVER TDSServer組件只有四個(gè)屬性,AutoStart,HideDSAdmin,Name和Tag.AutoStart屬性默認(rèn)設(shè)置為
TDSAdminMethods = class public const CreateServerClasses = 'DSAdmin.CreateServerClasses'; const CreateServerMethods = 'DSAdmin.CreateServerMethods'; const FindClasses = 'DSAdmin.FindClasses'; const FindMethods = 'DSAdmin.FindMethods'; const FindPackages = 'DSAdmin.FindPackages'; const GetPlatformName = 'DSAdmin.GetPlatformName'; const GetServerClasses = 'DSAdmin.GetServerClasses'; const GetServerMethods = 'DSAdmin.GetServerMethods'; const GetServerMethodParameters = 'DSAdmin.GetServerMethodParameters'; const DropServerClasses = 'DSAdmin.DropServerClasses'; const DropServerMethods = 'DSAdmin.DropServerMethods'; const GetDatabaseConnectionProperties = 'DSAdmin.GetDatabaseConnectionProperties'; end; TDSServer組件有五個(gè)事件:OnConnect,OnDisconnect,OnError,OnPrepare和OnTrace.我們可以 OnConnect,OnDisconnect,OnError和OnPrepare事件有一個(gè)繼承于TDSEventObject的參數(shù),包含 OnTrace事件有一個(gè)TDBXTraceInfo類型的參數(shù).注意由于這個(gè)OnTrace事件處理程序也會(huì)包含一 在OnConnect事件處理中,我們可以通過ChannelInfo來查看連接信息,例如(使用自定義的函數(shù) procedure TServerContainer1.DSServer1Connect( DSConnectEventObject: TDSConnectEventObject); begin LogInfo('Connect ' + DSConnectEventObject.ChannelInfo.Info); end; 在OnTrace事件處理程序中我們可以使用TraceInfo.Message中的信息記錄服務(wù)端正在做什么. function TServerContainer1.DSServer1Trace(TraceInfo: TDBXTraceInfo): CBRType; begin LogInfo('Trace ' + TraceInfo.CustomCategory); LogInfo(' ' + TraceInfo.Message); Result := cbrUSEDEF; // take default action end; 注意,在客戶端也可以使用連接到TSQLConnection組件的TSQLMonitor組件來跟蹤DataSnap服務(wù) 一個(gè)跟蹤日志輸出如下所示: 17:05:55.492 Trace 17:05:55.496 read 136 bytes:{"method":"reader_close","params":[1,0]}
"TServerMethods1.AS_GetRecords"]} 17:05:55.499 Prepare 如你所見,TraceInfo.Message中包括了傳輸信息的字節(jié)數(shù)和被調(diào)用的方法名稱等信息. 2.1.1.1.2. TDSSERVERCLASS TDSServerClass組件將服務(wù)端特定的類發(fā)布給遠(yuǎn)程客戶端(使用動(dòng)態(tài)方法調(diào)用). TDSServerClass組件有一個(gè)Server屬性指向TDSServer組件.其他除了Name和Tag外的重要屬 TDSServerClass有四個(gè)事件:OnCreateInstance,OnDestroyInstance(當(dāng)實(shí)例創(chuàng)建和注銷時(shí)觸 procedure TServerContainer1.DSServerClass1GetClass( DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); begin PersistentClass := ServerMethodsUnitDemo.TServerMethods1; end; 注意:當(dāng)我們重命名了自動(dòng)生成的代碼單元ServerMethodsUnit1為 2.1.1.1.3. TDSTCPSERVERTRANSPORT TDSTCPServerTransport組件負(fù)責(zé)在DataSnap服務(wù)端和客戶端進(jìn)行通訊,使用TCP/IP協(xié)議. TDSTCPServerTransport組件有五個(gè)重要的屬性:BufferKBSize,Filters(D2010新特 BufferKBSize屬性指定通訊緩沖區(qū)大小,默認(rèn)設(shè)置為32KB.Filters屬性可以包含一個(gè)傳輸過濾 Server屬性指向TDSServer組件.TDSTCPServerTransport組件沒有事件. 2.1.1.1.4. TDSHTTPSERVICE TDSHTTPService組件負(fù)責(zé)使用HTTP協(xié)議組織DataSnap服務(wù)端和客戶端通訊. TDSHTTPService組件有十個(gè)屬性(除了Name和 Active屬性指定DSHTTPService開始偵聽請(qǐng)求.可以在設(shè)計(jì)時(shí)設(shè)置,但是這會(huì)影響DataSnap服務(wù) procedure TServerContainer1.DataModuleCreate(Sender: TObject); begin DSHTTPService1.Active := True; end; AuthenticationManager屬性用于定義處理HTTP驗(yàn)證的管理組件,這里指向了 DSHostName和DSPort屬性用于定義DataSnap服務(wù)端連接,但只有在沒有指定Server屬性時(shí)生效.
Filters屬性可以包含一系列傳輸過濾器,在第四節(jié)詳述. HttpPort屬性定義DSHTTPService組件偵聽的特定端口以響應(yīng)連接.注意這個(gè)屬性默認(rèn)是80端口, RESTContext屬性指定REST上下文URL,這樣就可以以REST服務(wù)的方式調(diào)用DataSnap服務(wù).默 最后,Server屬性指向同一個(gè)容器中的TDSServer組件.如果沒有指定Server屬性,也可以使用 TDSHTTPService組件有五個(gè)事件:四個(gè)是REST相關(guān)的,一個(gè)是跟蹤事件,REST相關(guān)事件將在第六 OnTrace事件可用于跟蹤對(duì)DSHTTPService組件的調(diào)用,例如: procedure TServerContainer1.DSHTTPService1Trace(Sender: TObject; AContext: TDSHTTPContext; ARequest: TDSHTTPRequest; AResponse: TDSHTTPResponse); begin LogInfo('HTTP Trace ' + AContext.ToString); LogInfo(' ' + ARequest.Document); LogInfo(' ' + AResponse.ResponseText); end; 注意HTTP跟蹤信息只有當(dāng)客戶端使用HTTP連接到服務(wù)端是才會(huì)觸發(fā)(默認(rèn)使用TCP/IP協(xié)議). 跟蹤輸出如下所示: 17:05:55.398 HTTP Trace TDSHTTPContextIndy 17:05:55.400 /datasnap/tunnel 17:05:55.403 OK 從中可見,AContext設(shè)置為TDSHTTPContextIndy,ARequest設(shè)置為/DataSnap/tunnel,AResponse 2.1.1.1.5. TDSHTTPSERVICEAUTHENTICATIONMANAGER 當(dāng)選中HTTP通訊協(xié)議的驗(yàn)證復(fù)選框后,TDSHTTPServiceAuthenticationManager組件將自動(dòng)出現(xiàn) TDSHTTPServiceAuthenticationManager組件有一個(gè)事件:OnHTTPAuthenticate事件,可以驗(yàn)證 procedure TServerContainer1.DSHTTPServiceAuthenticationManager1HTTPAuthenticate( Sender: TObject; const Protocol, Context, User, Password: string; var valid: Boolean); begin if (User = 'Bob') and (Password = 'Swart') then valid := True else valid := False end; 當(dāng)然,你可以使用數(shù)據(jù)庫技術(shù)來擴(kuò)展驗(yàn)證方式.客戶端最好使用HTTPS方式將用戶名和密碼等 HTTPS可以確保連接安全和數(shù)據(jù)包加密, 數(shù)據(jù)包被竊取也不會(huì)泄露用戶和密碼信息.可與你所在
DataSnap服務(wù)應(yīng)用程序另一個(gè)優(yōu)勢(shì)是可將HTTP驗(yàn)證信息(所用協(xié)議和上下文信息)記錄下來.以 2.1.1.2. SERVERMETHODSUNITDEMO 注意我們已經(jīng)檢查了ServerContainerUnitDemo.pas單元,現(xiàn)在看一下DataSnap服務(wù)的另外重要 由于TServerMethods1繼承于TDataModule,設(shè)計(jì)時(shí)可以看到一個(gè)數(shù)據(jù)模塊的可視區(qū)域.我們可以 如果不想向項(xiàng)目組添加其他類型的項(xiàng)目—DataSnap控制臺(tái)應(yīng)用程序及DataSnap Windows服務(wù)應(yīng) 2.2. DATASNAP 客戶端 第一個(gè)DataSnap服務(wù)端范例啟動(dòng)并偵聽請(qǐng)求,現(xiàn)在創(chuàng)建一個(gè)客戶端.本節(jié)中,我們將講解如何在 確信DataSnap服務(wù)已啟動(dòng),我們創(chuàng)建一個(gè)DataSnap客戶端應(yīng)用程序項(xiàng)目.為了在設(shè)計(jì)時(shí)方便切換 DataSnap客戶端目錄中的組件都是一些老的DataSnap組件,可以使用,但不推薦.但可使用新 除了DataSnap客戶端目錄,我們還要看看dbEpress目錄,可以找到一個(gè)新的組件叫做 TSqlServerMethod組件可用于調(diào)用DataSnap服務(wù)的遠(yuǎn)程方法,但首先需要連接到DataSnap服務(wù). 可以使用TSQLConnect組件建立連接—--不在使用原來的TXXXConnection組件.為了靈活 注意:默認(rèn)CommunicationProtocol屬性為空,TSQLConnection將使用TCP/IP作為通信協(xié)議(端口 HostName,UserName和Password用于連接到DataSnap服務(wù).在本地測試時(shí),將HostName設(shè)置為 不要忘記將TSQLConnection的LoginPropt屬性設(shè)置為False,否則將會(huì)在連接的時(shí)候彈出登錄窗
一旦TSQLConnection的Driver屬性設(shè)置好,就可以設(shè)置Connected屬性為True去連接DataSnap服 2.2.1. DATASNAP客戶端類 在確定連接正常后,右擊TSQLConnection組件,選擇Generate DataSnap Class選項(xiàng),將生成一個(gè) 這個(gè)TServerMethods1Client類如下所示 type TServerMethods1Client = class private FDBXConnection: TDBXConnection; FInstanceOwner: Boolean; FEchoStringCommand: TDBXCommand; FServerTimeCommand: TDBXCommand; public constructor Create(ADBXConnection: TDBXConnection); overload; constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload; destructor Destroy; override; function EchoString(Value: string): string; function ServerTime: TDateTime; end; 如你所見,TServerMethods1Client類有兩個(gè)構(gòu)造方法,一個(gè)析構(gòu)方法和兩個(gè)我們?cè)诜?wù)端定義 為使用這些方法,將ServerMethodsClient單元引用到ClientForm,在客戶端窗體上放置一個(gè)按 procedure TForm2.Button1Click(Sender: TObject); var Server: TServerMethods1Client; begin Server := TServerMethods1Client.Create(SQLConnection1.DBXConnection); try ShowMessage(DateTimeToStr(Server.ServerTime)) finally Server.Free end; end; 這個(gè)代碼將創(chuàng)建一個(gè)TServerMethods1Client類實(shí)例,然后調(diào)用ServerTime服務(wù)類,最后釋放這 點(diǎn)擊按鈕將彈出對(duì)話框顯示服務(wù)端的時(shí)間.
2.2.1.1. HTTP COMMUNICATION PROTOCOL 注意我已經(jīng)提到TSQLConnection組件以TCP/IP作為默認(rèn)通訊協(xié)議.這樣我們就看不到任何HTTP 修改后運(yùn)行DataSnap客戶端,會(huì)出現(xiàn)如下錯(cuò)誤: 解決方法是在DataSnap客戶端向ClientForm中添加DSHTTPLayer單元引用. 2.2.1.2. HTTP 驗(yàn)證 使用HTTP通訊協(xié)議的好處之一是可以使用其包含的HTTP驗(yàn)證.由DataSnap服務(wù)端的 如果實(shí)現(xiàn)了OnHTTPAuthenticate事件處理,將會(huì)核對(duì)HTTP驗(yàn)證.我們必須保證輸入正確的信息才 HTTP檢驗(yàn)從客戶端傳遞到服務(wù)端的用戶名和密碼,及其他TDSHTTPServiceAuthentication特定 注意我們也需要指定HostName的值,除非是在同一臺(tái)電腦上測試. 2.3. DATASNAP服務(wù)部署 范例的服務(wù)端和客戶端在同一臺(tái)電腦上運(yùn)行良好,但是實(shí)際環(huán)境中,DataSnap服務(wù)將運(yùn)行在服務(wù) 2.3.1. DATASNAP 客戶端部署 假設(shè)客戶端與服務(wù)端運(yùn)行在不同的電腦上,我們必須保證客戶端可以連接到服務(wù)端.為了保證這 3. DATASNAP和數(shù)據(jù)庫 除了使用Delphi2010 DataSnap框架創(chuàng)建簡單的服務(wù)方法,我們還可以在服務(wù)端添加數(shù)據(jù)庫操作, 我們同樣可以快速創(chuàng)建數(shù)據(jù)庫操作的DataSnap范例,只使用SQLConnection組件和已創(chuàng)建的客戶 首先,我們要確保服務(wù)端公布了一個(gè)數(shù)據(jù)集,打開ServerMethodsUnitDemo并在數(shù)據(jù)模塊中添加
Users\Documents\RAD Studio\7.0\Demos\database\databases\BlackfishSQL on Windows XP, or C:\Users\Public\Documents\ RAD Studio\7.0\Demos\database\databases\BlackfishSQL. 下一步,添加一個(gè)TSQLDataSet組件,將其SQLConnection設(shè)置為TSQLConnection組件. 設(shè)置其CommandType為ctQuery,雙擊CommandText屬性輸入SQL語句. SELECT EMP_NO, FIRST_NAME, LAST_NAME, HIRE_DATE, JOB_COUNTRY FROM EMPLOYEE 確保在設(shè)計(jì)時(shí)設(shè)置了TSQLConnection組件的LoginPrompt和Connected屬性為False,及 現(xiàn)在在ServerMethodsUnitDemo單元的TServerMethods1類中添加一個(gè)public方法返回一個(gè) type
SQLConnection1: TSQLConnection; SQLDataSet1: TSQLDataSet; private { Private declarations } public { Public declarations } function EchoString(Value: string): string; function ServerTime: TDateTime; function GetEmployees: TDataSet; end; 如你所見,TServerMethods1類中定義了一個(gè)叫做GetEmployees的方法,實(shí)現(xiàn)如下: function TServerMethods1.GetEmployees: TDataSet; begin SQLDataSet1.Open; // make sure data can be retrieved Result := SQLDataSet1 end; 重新編譯服務(wù)并運(yùn)行.注意如你關(guān)閉了服務(wù)但無法重新編譯,可能是DataSnap服務(wù)還在運(yùn)行. 3.1. TSQLSERVERMETHOD 回到DataSnap客戶端,TSQLConnection組件應(yīng)該已經(jīng)斷開到DataSnap服務(wù)端的連接(如果仍然連 為了重寫原來的ServerMethodsClient單元,推薦從項(xiàng)目中移除原來的ServerMethodsClient后 type TServerMethods1Client = class private FDBXConnection: TDBXConnection; FInstanceOwner: Boolean; FEchoStringCommand: TDBXCommand; FServerTimeCommand: TDBXCommand; FGetEmployeesCommand: TDBXCommand; public constructor Create(ADBXConnection: TDBXConnection); overload; constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload; destructor Destroy; override; function EchoString(Value: string): string; function ServerTime: TDateTime; function GetEmployees: TDataSet; end; 為使用GetEmployees方法獲取TDataSet,我們可以使用TsqlServerMethod組件.將
本例我們選擇TServerMethods1.GetEmployees作為ServerMethodName屬性的值.根據(jù) 我們使用TDataSetProvider,TClientDataSet和TDataSource來使數(shù)據(jù)顯示在TDBGrid中. 在客戶端添加一個(gè)TDataSetProvider控件,將其DataSet設(shè)置為SqlServerMethod控件.下一步添 最后,放一個(gè)TDataSource控件,設(shè)置其DataSet為TClientDataSet控件,然后就可以放TGBGrid和 為了在設(shè)計(jì)時(shí)驗(yàn)證連接,我們?cè)O(shè)置ClientDataSet的Active屬性為True.將觸發(fā)SqlServerMethod 這種方式連接一直保持,TCliendtDataSet和TSQLConnection的被激活,數(shù)據(jù)顯示在TDBGrid中. 這種方式很容易以只讀方式查看數(shù)據(jù).注意這里說只讀,因?yàn)門SQLServerMethod不允許 TSQLServerMethod是輕量級(jí)方式連接獲取只讀數(shù)據(jù).這樣,如果你需要獲取DataSnap服務(wù)器上的 然而,有時(shí)我們需要更新數(shù)據(jù),這時(shí)就必須使用不同的方法獲取數(shù)據(jù). 3.2. TDSPROVIDERCONNECTION 如果我們想提交更新,我們就需要TDSProviderConnection組件與服務(wù)端的TDataSetProvider關(guān) 首先,我們需要修改服務(wù)端數(shù)據(jù)模塊,現(xiàn)有的只是返回一個(gè)TDataSet,我們必須添加一個(gè)實(shí)際的 現(xiàn)在,重新編譯DataSnap服務(wù),運(yùn)行.然后修改客戶端. 3.2.1. TDSPROVIDERCONNECTION 客戶端 為檢索到發(fā)布的TDataSetProvider組件需要修改一下DataSnap客戶端.將TSQLServerMethod和 在前一個(gè)例子中,TClientDataSet只設(shè)置了一個(gè)ProviderName屬性.然而,使用 在ProvideName屬性的下拉框中顯示dspEmployees選項(xiàng)(在服務(wù)端的ServerDataModule單元中發(fā) 現(xiàn)在我們可以設(shè)置TClientDataSet.Active為True,在設(shè)計(jì)時(shí)查看數(shù)據(jù). 設(shè)置TClientDataSet.Active為True,同時(shí)將TSQLConnection.Connected置為True.注意在設(shè)計(jì)
procedure TForm2.Button2Click(Sender: TObject); begin ClientDataSet1.Open; end; 現(xiàn)在添加代碼提交數(shù)據(jù)變更,保存回服務(wù)器. 3.2.2 數(shù)據(jù)庫更新 有兩種方法將數(shù)據(jù)修改保存會(huì)服務(wù)端:自動(dòng)和手動(dòng).都是調(diào)用一下方法,但是會(huì)自動(dòng)調(diào)用或手動(dòng) 對(duì)于自動(dòng)方式,我們可以使用TClientDataSet的數(shù)據(jù)修改時(shí)觸發(fā)的OnAfterInsert,OnAfterPost procedure TForm2.ClientDataSet1AfterPost(DataSet: TDataSet); begin ClientDataSet1.ApplyUpdates(0); end; 如果發(fā)生了更新錯(cuò)誤,將會(huì)觸發(fā)TClientDataSet的OnReconcileError事件,更多信息見3.2.3 手動(dòng)方式發(fā)生更新也是使用TClientDataSet的ApplyUpdates方法.但是這時(shí)方法不在 procedure TForm2.btnUpdateClick(Sender: TObject); begin ClientDataSet1.ApplyUpdates(0); end; 自動(dòng)提交的好處當(dāng)然用戶不會(huì)忘記將變更保存回服務(wù)端.然而,缺點(diǎn)是無法提供Undo能力.一旦 3.2.3. RECONCILE ERRORS TClientDataSet.ApplyUpdates方法有一個(gè)參數(shù):應(yīng)用更新時(shí)允許發(fā)生的最大錯(cuò)誤數(shù)量.如果有 幸運(yùn)的是,Delphi提供了一個(gè)很強(qiáng)大的對(duì)話框來處理這個(gè)問題.當(dāng)在DataSnap客戶端需要做一些 使用Delphi提供的功能,File.New.Other,在Delphi文件子目錄中選擇Reconcile Error對(duì)話框 選中這個(gè)圖標(biāo)點(diǎn)擊OK,保存為RecError.pas,加入到DataSnapClient項(xiàng)目.這個(gè)單元包括了定義 ReconcileErrorForm窗體實(shí)例將按需要?jiǎng)討B(tài)創(chuàng)建.那么如何使用這個(gè)特殊的ReconcileErrorForm窗體呢? procedure TForm2.ClientDataSet1ReconcileError(DataSet: TClientDataSet; E: EReconcileError; UpdateKind: TUpdateKind;
這個(gè)事件處理程序與四個(gè)參數(shù),第一個(gè)是拋出錯(cuò)誤的TClientDataSet,第二個(gè)參數(shù)是引發(fā)錯(cuò)誤沖 - raSkip:不更新這條記錄,但在變更日志中保留未提交的變更,下次提交在試. -raAbort:取消記錄沖突處理.. -raMerge:將更新記錄與遠(yuǎn)程數(shù)據(jù)庫記錄合并,僅在客戶端變更修改過的遠(yuǎn)程字段 -raCorrect:使用正確的值替換更新記錄,這需要用戶介入. -raCancel:對(duì)本記錄的修改全部放棄.回到初始值狀態(tài). -raRefresh:對(duì)本記錄修改全部放棄,但重新加載當(dāng)前數(shù)據(jù)庫的記錄值. 關(guān)于ReconcileErrorForm不需要考慮全部執(zhí)行選項(xiàng).只需要做兩件事件.一,在DataSnap客戶端主窗體中 procedure TFrmClient.ClientDataSet1ReconcileError(DataSet: TClientDataSet; E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction); begin Action := HandleReconcileError(DataSet, UpdateKind, E) end; 3.2.4. 示范沖突錯(cuò)誤 現(xiàn)在最大的問題是:實(shí)際工作中如何使用的沖突處理?為了測試,需要兩個(gè)或更多DataSnap客戶 -啟動(dòng)服務(wù)端應(yīng)用程序 -啟動(dòng)第一個(gè)客戶端應(yīng)用程序,點(diǎn)擊鏈接按鈕,獲取數(shù)據(jù) -啟動(dòng)第二個(gè)客戶端應(yīng)用程序,點(diǎn)擊鏈接按鈕,獲取數(shù)據(jù) -使用第一個(gè)客戶端應(yīng)用程序,修改第一行數(shù)據(jù)的FirstName列 -使用第二個(gè)客戶端應(yīng)用程序,修改第一行數(shù)據(jù)的FirstName列 -在第一個(gè)客戶端應(yīng)用程序中點(diǎn)擊更新按鈕 -在第二個(gè)客戶端應(yīng)用程序中點(diǎn)擊更新按鈕,這時(shí)將會(huì)發(fā)生一個(gè)或多個(gè)錯(cuò)誤.因?yàn)榈谝粋€(gè)應(yīng)用程 -進(jìn)入更新錯(cuò)誤對(duì)話框,現(xiàn)在可以處理沖突(忽略(Abort),取消(Abort),合并(Merge),更正(Correct),取消 Skip移動(dòng)到下一行記錄,忽略更新請(qǐng)求.但其更新將保留在更新日志中.Cancel也忽略更新請(qǐng)求 Refresh清除本記錄所有的變更記錄,并將數(shù)據(jù)庫中的值作為當(dāng)前記錄的值.Merge試圖將數(shù)據(jù)庫 Correct是一個(gè)強(qiáng)大的選項(xiàng),在事件處理中給你一個(gè)指定更新記錄值的機(jī)會(huì).需要寫代碼或彈出 3.3. DATASNAP 數(shù)據(jù)庫部署 部署一個(gè)使用數(shù)據(jù)庫的DataSnap服務(wù)需要比部署一個(gè)簡單DataSnap服務(wù)的步驟要多些.客戶端, 服務(wù)端,必須部署數(shù)據(jù)庫驅(qū)動(dòng).及所選數(shù)據(jù)庫依賴的驅(qū)動(dòng)和文件.使用DBX4,確保發(fā)布
Studio\dbExpress\7.0 directory on Windows XP or in the C:\Users\Public\Documents\RAD 3.4. 重用已有的遠(yuǎn)程數(shù)據(jù)模塊 如果你有一個(gè)遠(yuǎn)程數(shù)據(jù)模塊類,也可以將其組合到新的DataSnap項(xiàng)目中來.但是必須要犧牲一些特性,尤其 首先,如果有一個(gè)你要遷移的DataSnap服務(wù)應(yīng)用程序,而不僅僅是一個(gè)遠(yuǎn)程數(shù)據(jù)模塊,你需要使用命令行 {$IF CompilerVersion >= 20} initialization TComponentFactory.Create(ComServer, TRemoteDataModule2010, Class_RemoteDataModule2010, ciMultiInstance, tmApartment); {$IFEND} end. 從項(xiàng)目中移除UpdateRegistry函數(shù)或用編譯開關(guān)修飾: {$IF CompilerVersion >= 20} class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); override; {$IFEND} 最重要的變更—將項(xiàng)目轉(zhuǎn)換為無COM依賴的DataSnap服務(wù).-及移除類型庫(.ridl文件)和類型庫導(dǎo)入單元.這 4. DATASNAP 過濾器[FILTER]用法 本節(jié)將說明過濾器工作原理,及如何使用已存在的過濾器(如壓縮)或創(chuàng)建新的DataSnap過濾器.DataSnap 必須在客戶端和服務(wù)端指定過濾器.在服務(wù)端,必須指定TDSTCPServerTransport組件的過濾器屬性列表. 當(dāng)處理OnConnect事件時(shí),可以檢查用于連接的已注冊(cè)的過濾器,例如使用自定義的日志函數(shù)輸入日志信息, procedure TServerContainer1.DSServer1Connect( DSConnectEventObject: TDSConnectEventObject); var i: Integer; begin LogInfo('Connect ' + DSConnectEventObject.ChannelInfo.Info); for i:=0 to DSConnectEventObject.Transport.Filters.Count-1 do LogInfo(' Filter: ' + DSConnectEventObject.Transport.Filters.GetFilter(i).Id); end;
作為范例,我們使用已隨D2010提供的DataSnap過濾器.可用于在客戶端和服務(wù)端壓縮數(shù)據(jù)流.這里說的 TDSTCPServer和TDSHTTPService組件都有一個(gè)TTransportFiltersCollection類型的Filters屬性.點(diǎn)擊Filters 注意除了設(shè)置服務(wù)端TDSTCPServerTransport組件Filters屬性外,也需要在客戶端指定一個(gè)相應(yīng)的過濾器 如果沒有在客戶端添加DbxCompressionFilter單元引用,運(yùn)行客戶端后將會(huì)拋出異常信息: |
|
|