2013/04/17

自製懶人版的DbxDAC

因為SQLClientDataSet已經作廢,取而代之的SimpleDataSet 又搞不清那神奇的「InternalConnection」和詭異的「InternalDataSet」……

今天突發奇想,如果我自己做一個DbxDataSet呢?
製作上很簡單,底下來幾張簡圖:
一、新增VCL專案
二、新增Frame
Delphi XE的物件寶庫,選擇Frame
三、把Dbexpress(ADO亦可)相依的元件放進來並作好綁定工作
記得要把 DataSetProvider.Option的poAllowCommandText 設 True
DataSetProvider.Option的poAllowCommandText 設 True,這樣就可以直接對ClientDataSet下SQL指令。

為了讓它更像DataSet,所以我寫了以下的Code:
unit DbxDACUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, FMTBcd, DBClient, Provider, DB, SqlExpr;

type
  TDbxDataSet = class(TFrame)
    qy: TSQLQuery;
    dsp: TDataSetProvider;
    cds: TClientDataSet;
    procedure cdsAfterPost(DataSet: TDataSet);
    procedure cdsAfterDelete(DataSet: TDataSet);
    procedure cdsAfterCancel(DataSet: TDataSet);
  private
    function GetSQLConnection: TSQLConnection;
    procedure SetSQLConnection(const Value: TSQLConnection);
    procedure ApplyUpdates(DataSet: TDataSet);
    { Private declarations }
  public
    { Public declarations }
    property SQLConnection: TSQLConnection read GetSQLConnection write SetSQLConnection;
  end;

implementation

{$R *.dfm}

{ TDbxDataSet }

procedure TDbxDataSet.ApplyUpdates(DataSet: TDataSet);
begin
  cds.ApplyUpdates(0);
end;

procedure TDbxDataSet.cdsAfterCancel(DataSet: TDataSet);
begin
  cds.CancelUpdates();
end;

procedure TDbxDataSet.cdsAfterDelete(DataSet: TDataSet);
begin
  ApplyUpdates(DataSet);
end;

procedure TDbxDataSet.cdsAfterPost(DataSet: TDataSet);
begin
  ApplyUpdates(DataSet);
end;

function TDbxDataSet.GetSQLConnection: TSQLConnection;
begin
  Result := qy.SQLConnection;
end;

procedure TDbxDataSet.SetSQLConnection(const Value: TSQLConnection);
begin
  qy.SQLConnection := Value;
end;

end.

如此一來,在實作上就可以簡單用以下代碼:
procedure TForm1.Button1Click(Sender: TObject);
begin
  SQLConnection1.Open();
  DbxDataSet1.SQLConnection := SQLConnection1;
  DbxDataSet1.cds.CommandText := 'SELECT * FROM CDS ';
  DbxDataSet1.cds.Open();
end;

以上就是突發奇想的DbxDAC
如果有什麼想法和意見,請盡情地反饋一下吧!

2013/04/12

Devart Dbexpress driver for SQLite + Run-time created Encrypt Database

還記得這個網址嗎?
ID: 18385, SQLite DbExpress driver
當時可是使用內附的Demo時就悲劇了……

2008~2009年時我曾經有拿它來和Firebird作比較
當 C++ Builder 遇上 Firebird
關於dbExpress + SQLite3 怎麼用?



但事實上因為Bug無比多,所以我後來就放棄了Dbexpress + SQLite的方式


一直到Devart的出現才讓我又燃起了使用SQLite的慾望
本次介紹的主角--Devart Dbexpress driver for SQLite (*Photo from Devart)


為什麼要使用SQLite呢?

從綠色的羽毛就可以看出它的輕薄
答案很簡單,因為它能夠在不同的平台上被讀取、運作

iOS、Android上最常被用到的單機資料庫就是SQLite,如果同樣的資料庫架構可以輕鬆移轉到其它的平台上,那是多切愜意的事啊!

那麼,Devart這次要來變什麼魔術呢?

安裝步驟實在太簡單了,我就不再做介紹了

而企業上使用最常見的大概就是加密了,雖然解開後也沒什麼資料,但老闆們就是愛這一味……

而且沒問題的Demo重玩就沒意思了,哈!

所以我們就來介紹Devart的加密資料庫建立及資料表的使用吧

資料庫的建立?對,你沒聽錯,Devart的Dbexpress for SQLite driver是讓Dbexpress擁有自行建立資料庫的強大實力

首先我們要來打開Devart自帶的Demos:「%ProgramsFiles%\Devart\Dbx\SQLite\Demos\Win32\SimpleDataSet」

接下來就是設定SQLConnection.Params
參考Readme.htm的內容,我們得出以下的程式碼:
procedure TfmMain.edDatabaseExit(Sender: TObject);
begin
  if edDatabase.Text <> '' then
  begin
    SQLConnection.ConnectionName := 'Devart SQLite Direct';
    SQLConnection.DriverName := 'DevartSQLiteDirect';
    SQLConnection.LibraryName := 'dbexpsqlite40.dll';
    SQLConnection.GetDriverFunc := 'getSQLDriverSQLiteDirect';
    SQLConnection.Params.Clear;
    SQLConnection.Params.Add('DataBase='+edDatabase.Text);
    //存在時開啟,否則建立加密資料庫
    if FileExists(edDatabase.Text) then
    begin
      SQLConnection.Params.Add('ForceCreateDatabase=False');
      SQLConnection.Params.Add('EncryptionAlgorithm=Blowfish');
      SQLConnection.Params.Add('EncryptionKey=encryption key');
      SQLConnection.Params.Add('NewEncryptionKey=');
    end
    else
    begin
      SQLConnection.Params.Add('ForceCreateDatabase=True');
      SQLConnection.Params.Add('EncryptionAlgorithm=Blowfish');
      SQLConnection.Params.Add('EncryptionKey=');
      SQLConnection.Params.Add('NewEncryptionKey=encryption key');
    end;
  end
  else
    SQLConnection.Params.Values['Database'] := ' ';
end;

Project->Run後指定要建立的資料庫路徑及檔名,最後再按下「Open」,就建好囉!
按下「Open」鍵後,就可以看到資料庫建好而且也有Demo資料了


可是在Design Mode時想連結剛剛建立的加密資料庫,則會出現以下的錯誤視窗,我想可能之後的版本會改進吧。但目前只要Run-Time時期可以連就可以了
Design mode Error when TSQLConnection connect Encrypt database

以上就是 Devart Dbexpress driver for SQLite 的介紹,是不是也和我一樣覺得簡單又強大呢!

快去體驗Devart的Power吧!

2013/04/01

設定Double click間隔時間

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetDoubleClickTime(1500);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage(IntToStr(GetDoubleClickTime));
end;


資料來源:Get/set the doubleclick time

2013/03/15

Delphi xe2簡繁轉換函數

delphi xe2簡繁轉換函數  

function Cn2Big(CnStr: string): string;    //簡體中文轉繁體中文
var
 Len: Integer;
begin
 Len := Length(CnStr);
 SetLength(Result, Len);
 LCMapString(GetUserDefaultLCID, LCMAP_TRADITIONAL_CHINESE, PChar(CnStr), Len, PChar(Result), Len);
end;
//----------------------------------------
function Big2Cn(BigStr: string): string;   //繁體中文轉簡體中文
var
 Len: Integer;
begin
 Len := Length(BigStr);
 SetLength(Result, Len);
 LCMapString(GetUserDefaultLCID, LCMAP_SIMPLIFIED_CHINESE, PChar(BigStr), Len, PChar(Result), Len);
end;

關鍵是LCMapString的第二個參數,不同的值可以做許多不同的功能,如按字節倒轉、簡繁轉換、大小寫轉換等。函數原型如下:
int LCMapString( LCID, DWORD, LPCTSTR, int, LPTSTR, int);

2013/02/21

三層應用 webconnection與httpsrvr.dll與IIS的有關的問題

似乎可以改善WebConnection的連線狀況,有時間來試試


資料節錄如下:
改寫部分RemoteDataModule中的代碼:
線程模型(Threading Model)用Neutral
 /// Delphi
class procedure TEverydayInfoServer.UpdateRegistry(Register: Boolean; 
    const ClassID, ProgID: string);
begin
  if Register then
  begin
    inherited UpdateRegistry(Register, ClassID, ProgID);
    EnableWebTransport(ClassID);
    RegisterPooled(ClassID, 50, 1); //關鍵是這一句,用緩衝池的.
  end else
  begin
    DisableWebTransport(ClassID);
    UnregisterPooled(ClassID);
    inherited UpdateRegistry(Register, ClassID, ProgID);
  end;
end;

2015/ 02/19 更新
 // C++ Builder
  // Listing 21.1 UpdateRegistry to enable Connection Pooling
  // Function invoked to (un)register object
  //
  static HRESULT WINAPI UpdateRegistry(BOOL bRegister)
  {
  TRemoteDataModuleRegistrar regObj(GetObjectCLSID(),  GetProgID(), GetDescription());
  // Disable these flags to disable use by socket or Web connections.
  // Also set other flags to configure the behavior of your application server.
  // For more information, see atlmod.h and atlvcl.cpp.
  regObj.Singleton = false;
  regObj.MaxObjects = 10;
  regObj.Timeout = 42;
  regObj.RegisterPooled = true;
  regObj.EnableWeb = true;
  regObj.EnableSocket = true;
  return regObj.UpdateRegistry(bRegister);
  }

從 Document 來看,設定後會保留一個 RDM Instance,一併設定 Client 的最大連線數。

Client 連線數設定上限也可以達到節省 Database 的版權費用,的確可以參考使用。

資料來源: