Lazarus中文社区

 找回密码
 立即注册(注册审核可向QQ群索取)

QQ登录

只需一步,快速开始

Lazarus IDE and 组件 下载地址版权申明
查看: 5161|回复: 5

LAZARUS瘦客户端的实现

[复制链接]

该用户从未签到

发表于 2013-8-6 20:46:39 | 显示全部楼层 |阅读模式

  在D下我们用CLIENTDATASET来实现瘦客户端,在L下我用BUFDATASET来实现。主要思路和D完全一样,采用三层结构,后台用 SQLite3Connection、SQLTransaction和SQLQuery对数据库内容进行读写,通过SQLQuery的属性SaveToStream封装数据,然后传递到前台,用BUFDATASET的LoadFromStream加载,对BUFDATASET的操作再以逆路径传送回去,就实现了三层结构下的瘦客户端。
  以使用SQLITE3为例,新建DLL工程(library SqliteCon),添加一个DataModule窗体,放置SQLQuery等组件,编写相应代码,就将基本的数据库操作封装到DLL中,以后如需要更改数据库,只要改连接或更换相应组件就行。
  在DataModule中,取数据和更新数据的代码如下:
function TDM.GetData(Sqlstr: string): OleVariant;
var
   sqry:TSQLQuery;
   ms: TMemoryStream;
begin
   sqry:=TSQLQuery.create(nil);
   ms:= TMemoryStream.Create;
   try
     scon.Connected:=false;
     sqry.DataBase:=scon;
     scon.Connected :=true;
     sqry.Close ;
     sqry.SQL.Clear;
     sqry.SQL.Add(sqlstr);
     sqry.open ;
     sqry.SaveToStream(ms) ;
     ms.Position:=0;
     StreamToVariant (ms,result);
   finally
     scon.Connected:=false;
     freeandnil(sqry);
     freeandnil(ms);
   end;
end;
     scon.Connected:=false;
     freeandnil(sqry);
     freeandnil(ms);
   end;
end;
procedure TDM.UpdateData(TableStr,PrimaryKey: string; data: OleVariant);
var
   bufdt:TBufDataset;
   sqry:TSQLQuery;
   ms: TMemoryStream;
   s1,s2,sqlstr:string;
   i:integer;
begin
   sqry:=TSQLQuery.create(nil);
   SCon.Connected:=false;
   sqry.DataBase:=scon;
   scon.Connected :=true;
   ms:= TMemoryStream.Create;
   bufdt:=tbufdataset.Create(nil);
   try
     VariantToStream(data,ms);
     ms.Position:=0;
     bufdt.LoadFromStream(ms) ;
     if bufdt.RecordCount=0 then exit;
     bufdt.First ;
     while not bufdt.EOF do
     begin
        s1:=bufdt.FieldByName(PrimaryKey).AsString;
        s2:=PrimaryKey+'='+quotedstr(s1);
        sqlstr:='Select * from '+TableStr+' where '+s2  ;
        sqry.Close ;
        sqry.SQL.Clear;
        sqry.SQL.text:=sqlstr;
        sqry.open ;
        if sqry.FieldCount=bufdt.FieldCount then  //两个表必须相同
        begin
          if sqry.RecordCount=0 then
          sqry.Append
          else
          sqry.Edit;
          for i := 0 to sqry.FieldCount-1 do
          begin
            if bufdt.Fields[i].IsNull=false then
            sqry.Fields[i].Value:=bufdt.Fields[i].Value  ;
          end;
          sqry.post;
          sqry.ApplyUpdates ;
          sqltran.Commit ;
        end;
        bufdt.Next ;
     end;
   finally
     scon.Connected:=false;
     freeandnil(sqry);
     freeandnil(ms);
     freeandnil(bufdt);
   end;
end;
                         

回复

使用道具 举报

该用户从未签到

 楼主| 发表于 2013-8-6 20:48:34 | 显示全部楼层
Stream和Variant变量的转换如下:

procedure VariantToStream (const v : olevariant;Stream : TMemoryStream);
var
  p : pointer;
begin
  Stream.Position := 0;
  Stream.Size := VarArrayHighBound (v, 1) - VarArrayLowBound(v,  1) + 1;
  p := VarArrayLock (v);
  try
    Stream.Write (p^, Stream.Size);
  finally
    VarArrayUnlock (v);
  end;
    Stream.Position := 0;
end;

procedure StreamToVariant (Stream : TMemoryStream; var v : OleVariant);
var
  p : pointer;
begin
  v := VarArrayCreate ([0, Stream.Size - 1], varByte);
  p := VarArrayLock (v);
  Stream.Position := 0;
  try
    Stream.Read (p^, Stream.Size);
  finally
    VarArrayUnlock (v);
  end;
end;
               
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2013-8-6 20:52:21 | 显示全部楼层
DLL部分代码如下:
library SqliteCon;

{$mode objfpc}{$H+}

uses
  windows,Classes,forms,Interfaces,untdm,Types,SysUtils,Messages ;
  // windows,Classes,forms,Interfaces,untdm ;



procedure DLLEntryPoint(dwReason: DWord);
begin
  case dwReason of
  DLL_PROCESS_ATTACH:
  begin
    if not Assigned(DM) then
    DM:=TDM.Create(nil);
  end;
  DLL_PROCESS_DETACH:
  begin
    if Assigned(DM) then
    begin
      DM.SCon.Connected:=False;
      DM.Free;
    end;
  end;
  end;
end;

function GetData2(tablestrChar): OleVariant;stdcall ;
begin
  Result:=DM.GetData(PChar(tablestr));

end;

Procedure UpdateData2(TableStr,PrimaryKeyChar; data: OleVariant);stdcall;
begin
  DM.UpdateData(PChar(TableStr),Pchar(PrimaryKey),data);

end;


exports
    GetData2,UpdateData2;

begin

  DLLEntryPoint(DLL_PROCESS_ATTACH);

end.   

和DELPHI的DLL出入口略有区别,故全代码呈上。  
                                                           
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2013-8-6 20:54:28 | 显示全部楼层
本帖最后由 qqqqq 于 2013-8-6 20:55 编辑

通过上述步骤就可以将数据库组件等封装到DLL中了,剩下的就是调用了,明天再传前台应用代码。 
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2013-8-15 01:25:51 | 显示全部楼层
請問這樣寫出來的DLL部署在哪裡?是在客戶端,還是在服務器端?能夠用來連接服務器端的中間層嗎?例如.net、Java、PHP等寫出來的東西。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2013-12-25 10:11:48 | 显示全部楼层
貌似没下文了,不过思路已经有了
回复 支持 反对

使用道具 举报

*滑块验证:

本版积分规则

QQ|手机版|小黑屋|Lazarus中国|Lazarus中文社区 ( 鄂ICP备16006501号-1 )

GMT+8, 2025-5-3 00:45 , Processed in 0.033737 second(s), 9 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表