搜尋此網誌

2013/08/20

一個簡單的 Delphi O/R Mapping 工具

一個簡單的 Delphi O/R Mapping 工具。
這裡好像無法上傳檔案,需要者可與我聯絡:

  albertdongtw@gmail.com

或由此下載:

Download

Entity Builder主要的功能在於產生Delphi類別來對映(mapping)既有的資料表。基本上,資料表的欄位會對映到Delphi類別的屬性(property)。但是手動做這些工作是非常辛苦的,所以我們可以使用這個工具程式來建立基本的類別骨架。
執行程式後的啟始畫面。


按下「建立ADO連線」按鈕設定ADO連線。

接著如同使用TADOConnection元件般設定ConnectionString



此時會顯示資料庫與資料表(不含系統資料表)清單。

由資料表清單選擇一個資料表。


按「預覽」按鈕即可顯示產生的程式碼。可按滑鼠右鍵儲存到檔案或是複製到剪貼簿。




  
產生出來的完整程式碼如下:
{-------------------------------------------------------------------------------
This file is generated by EntityBuilder v1.2
provided by Albert Dong, albertdongtw@gmail.com

The Template Engine is from:
    http://sourceforge.net/projects/delphi-templeng/
--------------------------------------------------------------------------------

Class: User
Table: user
Author: XXX
Date: 2013/8/20 下午 07:06:39
Description:
-------------------------------------------------------------------------------}

unit uUser;

interface

uses
  Windows, Messages, SysUtils, Variants, Contnrs, Classes, DB, uEntity;

const
  TBL_User = 'user';

type
  {**
   * Class description.
   *
   * @author XXX, 2013/08/20 19:06:39. Created.
   *}
  TUser = class(TEntity)
  private
    // ------ Fields ------
    FNo: string;
    FName: string;
    FNameEng: string;
    FEmail: string;
    FRecvCalNotify: integer;
    FRecvCalOverdue: integer;
    FIsAdmin: integer;

  protected
    // ------ Property Accessors ------
    function GetNo: string;
    procedure SetNo(value: string);

    function GetName: string;
    procedure SetName(value: string);

    function GetNameEng: string;
    procedure SetNameEng(value: string);

    function GetEmail: string;
    procedure SetEmail(value: string);

    function GetRecvCalNotify: integer;
    procedure SetRecvCalNotify(value: integer);

    function GetRecvCalOverdue: integer;
    procedure SetRecvCalOverdue(value: integer);

    function GetIsAdmin: integer;
    procedure SetIsAdmin(value: integer);


    procedure FillData(DataSet: TDataSet); override;

  public
    // ------ Utility Class Methods ------
    class function ListAll: TList;
    class procedure DeleteAll;

    constructor Create; override;
    destructor Destroy; override;

    function ToString: string; override;

    procedure Reload;
    procedure Insert;
    procedure Update;
    procedure Delete;

  published
    // ------ Properties ------
    property No: string read GetNo write SetNo;
    property Name: string read GetName write SetName;
    property NameEng: string read GetNameEng write SetNameEng;
    property Email: string read GetEmail write SetEmail;
    property RecvCalNotify: integer read GetRecvCalNotify write SetRecvCalNotify;
    property RecvCalOverdue: integer read GetRecvCalOverdue write SetRecvCalOverdue;
    property IsAdmin: integer read GetIsAdmin write SetIsAdmin;
  end;

implementation

uses
  uToString;

{ TUser }

class function TUser.ListAll: TList;
var
  stmt: string;
begin
  stmt := 'SELECT * FROM ' + TBL_User;
  result := TEntity.ExecQueryForList(stmt, TUser);
end;

class procedure TUser.DeleteAll;
begin
  ExecUpdate('DELETE FROM ' + TBL_User);
end;

constructor TUser.Create;
begin
  inherited Create;
  // TODO: Constructor...
end;

destructor TUser.Destroy;
begin
  // TODO: Destructor...
  inherited Destroy;
end;

(**
 * Fill object properties with the specified dataset.
 * Every subclass of TEntity inherits AsXXX() methods.
 *
 * @param DataSet the specified dataset.
 *)
procedure TUser.FillData(DataSet: TDataSet);
begin
  if DataSet = nil then
    raise Exception.Create('Nil DataSet!');

  if DataSet.IsEmpty or DataSet.Eof then
    Exit;

    FNo := AsString(DataSet, 'no');
    FName := AsString(DataSet, 'name');
    FNameEng := AsString(DataSet, 'name_eng');
    FEmail := AsString(DataSet, 'email');
    FRecvCalNotify := AsInteger(DataSet, 'recv_cal_notify');
    FRecvCalOverdue := AsInteger(DataSet, 'recv_cal_overdue');
    FIsAdmin := AsInteger(DataSet, 'is_admin');
end;

procedure TUser.Reload;
var
  stmt: string;
begin
  stmt := 'SELECT * FROM ' + TBL_User
        + ' WHERE 1 = 1 '
        + '   AND no = ' + QuotedStr(No)
    ;

  TEntity.Load(stmt, self);
end;

procedure TUser.Insert;
var
  stmt: string;
begin
  stmt := 'INSERT INTO ' + TBL_User + ' ('

        + 'no'

        + ', name'

        + ', name_eng'

        + ', email'

        + ', recv_cal_notify'

        + ', recv_cal_overdue'

        + ', is_admin'

        + ') VALUES ('

        + QuotedStr(No)

        + ', ' + QuotedStr(Name)

        + ', ' + QuotedStr(NameEng)

        + ', ' + QuotedStr(Email)

        + ', ' + IntToStr(RecvCalNotify)

        + ', ' + IntToStr(RecvCalOverdue)

        + ', ' + IntToStr(IsAdmin)
        + ') '
    ;

  ExecUpdate(stmt);
end;

procedure TUser.Update;
var
  stmt: string;
begin
  stmt := 'UPDATE ' + TBL_User + ' SET '

        + 'no = ' + QuotedStr(No)

        + ', name = ' + QuotedStr(Name)

        + ', name_eng = ' + QuotedStr(NameEng)

        + ', email = ' + QuotedStr(Email)

        + ', recv_cal_notify = ' + IntToStr(RecvCalNotify)

        + ', recv_cal_overdue = ' + IntToStr(RecvCalOverdue)

        + ', is_admin = ' + IntToStr(IsAdmin)

        + ' WHERE 1 = 1 '
        + '   AND no = ' + QuotedStr(No)
    ;

  ExecUpdate(stmt);
end;

procedure TUser.Delete;
var
  stmt: string;
begin
  stmt := 'DELETE FROM ' + TBL_User
      + ' WHERE 1 = 1 '
      + '   AND no = ' + QuotedStr(No)
    ;
  ExecUpdate(stmt);
end;

function TUser.ToString: string;
begin
  TToStringBuilder.toString(self);
end;

function TUser.GetNo: string;
begin
  result := FNo;
end;

procedure TUser.SetNo(value: string);
begin
  if FNo <> value then begin
    FNo := value;
  end;
end;

function TUser.GetName: string;
begin
  result := FName;
end;

procedure TUser.SetName(value: string);
begin
  if FName <> value then begin
    FName := value;
  end;
end;

function TUser.GetNameEng: string;
begin
  result := FNameEng;
end;

procedure TUser.SetNameEng(value: string);
begin
  if FNameEng <> value then begin
    FNameEng := value;
  end;
end;

function TUser.GetEmail: string;
begin
  result := FEmail;
end;

procedure TUser.SetEmail(value: string);
begin
  if FEmail <> value then begin
    FEmail := value;
  end;
end;

function TUser.GetRecvCalNotify: integer;
begin
  result := FRecvCalNotify;
end;

procedure TUser.SetRecvCalNotify(value: integer);
begin
  if FRecvCalNotify <> value then begin
    FRecvCalNotify := value;
  end;
end;

function TUser.GetRecvCalOverdue: integer;
begin
  result := FRecvCalOverdue;
end;

procedure TUser.SetRecvCalOverdue(value: integer);
begin
  if FRecvCalOverdue <> value then begin
    FRecvCalOverdue := value;
  end;
end;

function TUser.GetIsAdmin: integer;
begin
  result := FIsAdmin;
end;

procedure TUser.SetIsAdmin(value: integer);
begin
  if FIsAdmin <> value then begin
    FIsAdmin := value;
  end;
end;


initialization
  // Register this entity class for dynamic loading.
  RegisterClass(TUser);

finalization
  UnRegisterClass(TUser);


end. 


2012/07/19

AJAX Web 自動化

  • 試用 ExtJS 4.1
  • 以Tomcat 7.0 做為
  • 使用 DWR 做為橋接browser與server的framework。
  • 使用 Apache OJB + XDoclet 為 O/R mapping framework。
  • 資料庫使用MySQL
  • 透過 ICPDAS I-7188 連接 永宏(Fatek)的 PLC ==> Fatek prorotol
  • ICPDAS 簡訊機。  ==> Modbus/RTU over TCP


監控畫面

 細節

 即地編輯(In-Place Editing)


查詢與報表(PDF)

2012/04/30

在Delphi匯入WMP ActiveX控制項

在Delphi匯入WMP ActiveX控制項

有兩個Media Player,應選擇TWindowsMediaPlayer (wmp.dll),而不是TMediaPlayer (msdxm.ocx)
因為Delphi內建已安裝TMediaPlayerSystem元件盤。


最後應該會安裝至ActiveX元件盤,元件名稱為WindowsMediaPlayer



與房仲相關的概念模型


2012/04/27

SPC Show Chart 探討

SPC Show Chart 探討

在這份文件中,我將再深入探討SPC Client的中以各種形式呈現Chart的設計模型(OOD Model)
我的目標是提出一套考慮更為完整的物件導向設計,使得在接下來的實作階段中能夠花最少的力氣以更有效率地完成程式實作,同時仍然能夠保持軟體品質,易於除錯,易於閱讀與維護,以及易於因應軟體的改變(降低軟體的改變的成本與時間)
當然了,實作之中永遠會有更多煩人的細節,有些細節可能會影響到本次設計的模型架構。但是我們預期此部分的問題可以等待至本設計的核心實作出來後,再以程式重整(Refactoring)的手法來回頭修改(Refine)本次設計的模型架構。
這份文件不會提到任何與使用者介面相關的技術,如果您需要此類的資訊,您應該去查閱Borland C++ BuilderC/C++程式語言的相關文件。另外這份文件也儘量不去提及與特定程語言相關的論題,僅當實際的設計模型使用到與特定程語言相關的技術時,我才會加以說明。同時我也假定您對設計樣式(Design Pattern)已具有相當程度的瞭解,所以我也不會對所模型中所引用的設計樣式做過多的細節解釋 已經有許多的書籍及文章完成這個工作,如果需要的話,您應該先去閱讀這些書籍及文章。
特別聲明: 
我已經儘量參考目前所能夠得到的資訊來寫作這份文件,同時我也已盡力維持設計的正確性與一致性,但是其中或許仍有疏漏。如果有任何人發現的話,請不吝告訴我。謝謝! 

目前SPC模組有7Chart,而每一個Chart都必須支援3種呈現方式(On-Line ChartOff-Line Chart,以及Report),要如何解決Chart與呈現方式的「配對問題」(7x3)?同時仍保有彈性與擴充性?
1.           ChartType抽象出來:每一個Chart可以想成ChartDefChartType的組合。而當ChartType被決定的同時,很多其他的事物亦同時決定了。
注意:此處的ChartType抽象類別



2.         ChartTypeHistogramChartParetoChart,…等7 (這裡繪出2種做為代表)。這是一種利用Object Composition達成C/V的方式。




3.         ChartDisplayChartType分離出來。其具體子類別有OnLineDisplayOffLineDisplay,及ReportDisplay。注意:此處的ChartDisplay是抽象類別。

4.         定義ChartForm抽象類別。ChartForm物件有責任執行真正的Chart顯示與報表產生的工作。它有3個主要的Methods

    1. showChart()
    2. showOffLineChart()
    3. showReport()

ChartForm的子類別理想上應該就是實際的UI物件(例如BCBTForm物件) ,但是實際上恐怕很難達成此要求,同時又為了增加彈性(實際的UI物件可能會改變),所以我們可以使用Adapter樣式來處理實際的UI物件(見下一步驟)



5.         完成!!

每個ChartType物件有責任建立出正確的ChartForm物件(Expert樣式)。當ChartDefdisplay方法被呼叫時,ChartDef物件會將此呼叫委任給其內含的ChartType物件的display方法處理,而ChartType物件的display方法會根據子代類別的override版本來執行(多型),而ChartType物件的display方法其實也是將此呼叫委任給其內含的ChartDisplay物件去處理。而到此處,ChartDisplay物件才會將此呼叫委任給真正執行任務的ChartForm物件。

此處值得注意的地方在於ChartForm的子類別往往只是一個Adapter(Wrapper),其目的在於使得我們可以以一致的介面處理背後的UI物件(這裡的UI物件即是BCB中的Form物件,而此Form物件上已有QCToolsSPC繪畫元件,但是此Form物件未必會繼承ChartForm)。所以圖中的HistogramChartFormParetoChartForm類別即扮演著Adapter的角色。其典型的做法即是使用Object Composition的方式包裝實際的UI物件(Form物件),然後將呼叫委任給其所內含的UI物件處理。



1.           這裡的解決方案中如果以C/V (Commonalities/Variabilities)分析(CVA)的角度來看,ChartDefChartTypeChartDisplay,以及ChartForm類別即代表了Commonalities (見下圖),也就是代表一個共同的抽象概念。而Commonality類別的子類別則代表了Variabilities
這種手法可以讓抽象類別來「封裝」Variation (也就是物件導向所說的「易於修改),但又能讓系統保持概念上的穩定性。所以請記注一句物件導向的內功心法:「Abstraction is the key!

2.         此例多處利用抽象類別封裝具體類別的方式「封裝」的新觀點。因為具體類別即代表系統中可能變動的部分,所以此符合物件導向中的「Find What Varies and Encapsulate It!」原則。
3.         封裝行為「封裝」的另一新觀點。分析問題時不要認為「封裝」只是指「資料隱藏」,而要採用更為廣義的定義「封裝指封裝任何事物」。此例的哲學即在於「封裝display的行為」。
4.         此例的關鍵處大部分使用Object Composition而非Class Inheritance。此亦符合「Favor Object Composition than Class Inheritance」原則。
5.         Adapter樣式不僅只是用來轉換不同的介面而已!其真正的價值在於讓我們在設計時無須擔心有任何具體類別無法符合我們的模型。因為有了Adapter樣式,我們可以轉換任何介面不符合的類別。