Lazarus中文社区

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

QQ登录

只需一步,快速开始

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

Lazarus下三层架构的实体类代码生成及应用

[复制链接]

该用户从未签到

发表于 2013-8-13 09:31:27 | 显示全部楼层 |阅读模式
1、ORM技术概述
    对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
    面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。
    让我们从O/R开始。字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。
    当你开发一个应用程序的时候(不使用O/R Mapping),你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。你在DAL中写了很多的方法来读取对象数据,改变状态对象等等任务。而这些代码写起来总是重复的。
    如果打开你最近的程序,看看DAL代码,你肯定会看到很多近似的通用的模式。我们以保存对象的方法为例,你传入一个对象,为SqlCommand对象添加SqlParameter,把所有属性和对象对应,设置SqlCommand的CommandText属性为存储过程,然后运行SqlCommand。对于每个对象都要重复的写这些代码。
除此之外,还有更好的办法吗?有,引入一个O/R Mapping。实质上,一个O/R Mapping会为你生成DAL。与其自己写DAL代码,不如用O/R Mapping。你用O/R Mapping保存,删除,读取对象,O/R Mapping负责生成SQL,你只需要关心对象就好。
    在三层架构下,这种ORM技术通常用在服务端业务逻辑部件的实现上,一般不推荐在客户端直接使用这种Object,因为,客户端实现业务逻辑与三层架构的原则是相背离的,客户端只管表现,不要去处理业务逻辑。
    然而,实际开发了三层架构应用系统之后我们会发现,有时候在客户端适当地处理一些简单的业务逻辑还是需要的,特别是有利于提高应用开发效率(应用程序员两层架构下的开发经验可以沿用下来),避免了无论巨细都需要写业务逻辑部件的弊端。鉴于此,我们在QuickBurro中向应用程序员提供了将数据表直接映射为客户端Object的工具,以帮助应用程序员快速方便地得到数据表所映射到的对象的实现代码。

2、实体类代码生成工具
    QuickBurro中所带的GetEntity.exe工具,就是上述将数据表Mapping到对象、自动生成对象的实现代码的工具。截止到V4.28,此工具已经能生成For Delphi桌面程序的实体类、For FireMonkey的移动开发程序的实体类,以及,这里所关心的Lazarus三层应用开发用的实体类。具体使用上,该工具支持按如下四种方式生成实体类:
a)、简单实体: 简单地将一个选中的数据表映射为一个对象、自动生成该实体对象的Delphi代码、FireMonkey代码、或者Lazarus代码。
b)、批量实体: 选中多个数据表时,自动、批量地生成对应的实体类代码。
c)、动态实体: 指定一个SQL语句,再根据返回的数据集来生成对应的实体类代码。
d)、主从实体: 指定主表、各从表,以及之间的关联字段,自动生成其方法能自动维护其主从关系的实体类的代码。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册(注册审核可向QQ群索取)

x
回复

使用道具 举报

该用户从未签到

 楼主| 发表于 2013-8-13 09:33:42 | 显示全部楼层
3、来看一个实际的实体类完整代码
GetEntity工具所生成的实体类代码中包含了与单个记录对应的基本对象Lazarus(或delphi,下同)代码、以及与一个数据集对应的对象列表对象的Lazarus代码。其中,基本对象实体提供的方法及其功能说明如下:
//
// 对象构造方法…
    constructor Create;
//
// 析构方法…
    destructor Destroy; override;
//
// 从内存表TMemDataset读一个记录、转换为当前对象…
    function ReadFromMds(aMds: TMemDataset): boolean;
//
// 将本对象的属性保存到内存表中,生成一个记录…
    function SaveToMds(Mds: TMemDataset): Boolean;
//
// 根据条件从远程数据库中过滤出一个记录并转换为当前对象…
    function ReadFromDB(DBA: TLazAccessor; Condition: String): boolean;
//
// 将当前对象对应的记录从远程数据表中删除…
    function DeleteFromDB(DBA: TLazAccessor; Condition: String): boolean;
//
// 将当前对象追加到远程数据表中…
    function InsertToDB(DBA: TLazAccessor): boolean;
//
// 将当前对象属性更新到数据表中的对应记录中…
    function UpdateToDB(DBA: TLazAccessor; Condition: String): boolean;
//
// 判定属性是否为空…
    function PropIsNull(PropName: string): boolean;
//
// 设置一个属性为空…
    function SetPropNull(PropName: string): boolean;
对象列表对象是基于Tlist基类生成的子类,包含如下方法:
//
// 清除列表…
    procedure Clear; override;   
//
// 从远程数据库读取数据集并转换为对象列表…
    function ReadFromDB(DBA: TLazAccessor; Condition: String = ''; OrderBy: String = ''): Boolean;
//
// 将MemDataset中的一系列记录转换为对象列表…
    function ReadFromMDS(Mds: TMemDataset): Boolean;
//
// 将对象列表转换为数据集…
    function SaveToMds(var Mds: TMemDataset): boolean;
//
// 将对象列表追加到远程数据库中…
    function InsertToDB(DBA: TLazAccessor): boolean;
//
// 将对象列表中的对象更新到远程数据库中…
    function UpdateToDB(DBA: TLazAccessor; Condition: String): boolean;
//
// 从远程数据库中删除对象对应的记录…
    function DeleteFromDB(DBA: TLazAccessor; Condition: String): boolean;
//
// 将对象列表导出到文件…
    function SaveToFile(FileName: String): boolean;
//
// 从文件导入数据、转换为对象列表…
    function LoadFromFile(FileName: String): boolean;
//
// 将对象列表数据导出到流对象…
    function SaveToStream(aStream: TMemoryStream): boolean;
//
// 从流对象导入对象列表…
    function LoadFromStream(aStream: TMemoryStream): boolean;
由以上方法可以看出,通过对象的创建、导入导出等方法,就可以实现与数据库之间的交互,通过对象的属性,可以访问数据库字段值,通过对象之间的属性关联关系,可以用来处理表间关系等等,应用程序写起来会更省力,不再需要了解与数据库读写的底层方法。 下面给出一个完整的简单实体类的代码,主从构造类实体类代码只在此基础上增加了关联处理部分,请您自己去了解:

//
// ------------------------------------------------------------------------------------
//
// Entity_Customers.pas -- 数据表"Customers"对应的Lazarus实体类单元。
//
//                          本单元由QuickBurro V4.2.8.0 实体类生成器(GetEntity)所生成。
//
//                          生成时间: 2013-08-13 09:24:54
//
//                          版权所有(C) 樵夫软件工作室(Jopher Software Studio), 2006-2013
//
// ------------------------------------------------------------------------------------
//
unit Entity_Customers;
interface
uses
   SysUtils,
   Classes,
   db,
   Memds,
   LazAccessor,
   LazParcel;
type
  TCustomers = class(TObject)
  Private
    ff_CustomerID: String;
    ff_CompanyName: String;
    ff_ContactName: String;
    ff_ContactTitle: String;
    ff_Address: String;
    ff_City: String;
    ff_Region: String;
    ff_PostalCode: String;
    ff_Country: String;
    ff_Phone: String;
    ff_Fax: String;
    ff_Peoples: Int64;
    flag_CustomerID: boolean;
    flag_CompanyName: boolean;
    flag_ContactName: boolean;
    flag_ContactTitle: boolean;
    flag_Address: boolean;
    flag_City: boolean;
    flag_Region: boolean;
    flag_PostalCode: boolean;
    flag_Country: boolean;
    flag_Phone: boolean;
    flag_Fax: boolean;
    flag_Peoples: boolean;
    procedure Set_CustomerID(_CustomerID: String);
    procedure Set_CompanyName(_CompanyName: String);
    procedure Set_ContactName(_ContactName: String);
    procedure Set_ContactTitle(_ContactTitle: String);
    procedure Set_Address(_Address: String);
    procedure Set_City(_City: String);
    procedure Set_Region(_Region: String);
    procedure Set_PostalCode(_PostalCode: String);
    procedure Set_Country(_Country: String);
    procedure Set_Phone(_Phone: String);
    procedure Set_Fax(_Fax: String);
    procedure Set_Peoples(_Peoples: Int64);
  public
    Property f_CustomerID: String read ff_CustomerID write Set_CustomerID;
    Property CustomerID_Updated: boolean read flag_CustomerID write flag_CustomerID;
    Property f_CompanyName: String read ff_CompanyName write Set_CompanyName;
    Property CompanyName_Updated: boolean read flag_CompanyName write flag_CompanyName;
    Property f_ContactName: String read ff_ContactName write Set_ContactName;
    Property ContactName_Updated: boolean read flag_ContactName write flag_ContactName;
    Property f_ContactTitle: String read ff_ContactTitle write Set_ContactTitle;
    Property ContactTitle_Updated: boolean read flag_ContactTitle write flag_ContactTitle;
    Property f_Address: String read ff_Address write Set_Address;
    Property Address_Updated: boolean read flag_Address write flag_Address;
    Property f_City: String read ff_City write Set_City;
    Property City_Updated: boolean read flag_City write flag_City;
    Property f_Region: String read ff_Region write Set_Region;
    Property Region_Updated: boolean read flag_Region write flag_Region;
    Property f_PostalCode: String read ff_PostalCode write Set_PostalCode;
    Property PostalCode_Updated: boolean read flag_PostalCode write flag_PostalCode;
    Property f_Country: String read ff_Country write Set_Country;
    Property Country_Updated: boolean read flag_Country write flag_Country;
    Property f_Phone: String read ff_Phone write Set_Phone;
    Property Phone_Updated: boolean read flag_Phone write flag_Phone;
    Property f_Fax: String read ff_Fax write Set_Fax;
    Property Fax_Updated: boolean read flag_Fax write flag_Fax;
    Property f_Peoples: Int64 read ff_Peoples write Set_Peoples;
    Property Peoples_Updated: boolean read flag_Peoples write flag_Peoples;
    constructor Create;
    destructor Destroy; override;
    function ReadFromMds(aMds: TMemDataset): boolean;
    function SaveToMds(Mds: TMemDataset): Boolean;
    function ReadFromDB(DBA: TLazAccessor; Condition: String): boolean;
    function DeleteFromDB(DBA: TLazAccessor; Condition: String): boolean;
    function InsertToDB(DBA: TLazAccessor): boolean;
    function UpdateToDB(DBA: TLazAccessor; Condition: String): boolean;
    function PropIsNull(PropName: string): boolean;
    function SetPropNull(PropName: string): boolean;
  end;
  TCustomersList = class(TList)
  public
    procedure Clear; override;   
    function ReadFromDB(DBA: TLazAccessor; Condition: String = ''; OrderBy: String = ''): Boolean;
    function ReadFromMDS(Mds: TMemDataset): Boolean;
    function SaveToMds(var Mds: TMemDataset): boolean;
    function InsertToDB(DBA: TLazAccessor): boolean;
    function UpdateToDB(DBA: TLazAccessor; Condition: String): boolean;
    function DeleteFromDB(DBA: TLazAccessor; Condition: String): boolean;
    function SaveToFile(FileName: String): boolean;
    function LoadFromFile(FileName: String): boolean;
    function SaveToStream(aStream: TMemoryStream): boolean;
    function LoadFromStream(aStream: TMemoryStream): boolean;
   
  end;
implementation
//
// 创建Mds容器,用于记录数据的本地暂存...
function CreateMds: TMemDataset;
begin
  Result:=TMemDataset.Create(nil);
  with Result do
     begin
        with FieldDefs.AddFieldDef do
           begin
              Name:='CustomerID';
              DataType:=ftString;
              Size:=5;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='CompanyName';
              DataType:=ftString;
              Size:=40;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='ContactName';
              DataType:=ftString;
              Size:=30;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='ContactTitle';
              DataType:=ftString;
              Size:=30;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='Address';
              DataType:=ftString;
              Size:=60;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='City';
              DataType:=ftString;
              Size:=15;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='Region';
              DataType:=ftString;
              Size:=15;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='PostalCode';
              DataType:=ftString;
              Size:=10;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='Country';
              DataType:=ftString;
              Size:=15;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='Phone';
              DataType:=ftString;
              Size:=24;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='Fax';
              DataType:=ftString;
              Size:=24;
           end;
        with FieldDefs.AddFieldDef do
           begin
              Name:='Peoples';
              DataType:=ftLargeint;
           end;
        CreateTable;
     end;
  Result.Open;
end;
{ TCustomers }
//
// 属性设置的一系列内部过程...
procedure TCustomers.Set_CustomerID(_CustomerID: String);
begin
   ff_CustomerID:=_CustomerID;
   flag_CustomerID:=true;
end;
procedure TCustomers.Set_CompanyName(_CompanyName: String);
begin
   ff_CompanyName:=_CompanyName;
   flag_CompanyName:=true;
end;
procedure TCustomers.Set_ContactName(_ContactName: String);
begin
   ff_ContactName:=_ContactName;
   flag_ContactName:=true;
end;
procedure TCustomers.Set_ContactTitle(_ContactTitle: String);
begin
   ff_ContactTitle:=_ContactTitle;
   flag_ContactTitle:=true;
end;
procedure TCustomers.Set_Address(_Address: String);
begin
   ff_Address:=_Address;
   flag_Address:=true;
end;
procedure TCustomers.Set_City(_City: String);
begin
   ff_City:=_City;
   flag_City:=true;
end;
procedure TCustomers.Set_Region(_Region: String);
begin
   ff_Region:=_Region;
   flag_Region:=true;
end;
procedure TCustomers.Set_PostalCode(_PostalCode: String);
begin
   ff_PostalCode:=_PostalCode;
   flag_PostalCode:=true;
end;
procedure TCustomers.Set_Country(_Country: String);
begin
   ff_Country:=_Country;
   flag_Country:=true;
end;
procedure TCustomers.Set_Phone(_Phone: String);
begin
   ff_Phone:=_Phone;
   flag_Phone:=true;
end;
procedure TCustomers.Set_Fax(_Fax: String);
begin
   ff_Fax:=_Fax;
   flag_Fax:=true;
end;
procedure TCustomers.Set_Peoples(_Peoples: Int64);
begin
   ff_Peoples:=_Peoples;
   flag_Peoples:=true;
end;

//
// 创建对象实例...
constructor TCustomers.Create;
begin
  inherited;
  ff_CustomerID:='';
  flag_CustomerID:=false;
  ff_CompanyName:='';
  flag_CompanyName:=false;
  ff_ContactName:='';
  flag_ContactName:=false;
  ff_ContactTitle:='';
  flag_ContactTitle:=false;
  ff_Address:='';
  flag_Address:=false;
  ff_City:='';
  flag_City:=false;
  ff_Region:='';
  flag_Region:=false;
  ff_PostalCode:='';
  flag_PostalCode:=false;
  ff_Country:='';
  flag_Country:=false;
  ff_Phone:='';
  flag_Phone:=false;
  ff_Fax:='';
  flag_Fax:=false;
  ff_Peoples:=0;
  flag_Peoples:=false;
end;
//
// 释放对象实例...
destructor TCustomers.Destroy;
begin
  inherited;
end;
//
// 将Mds中的当前记录转换为对象实例...
function TCustomers.ReadFromMds(aMds: TMemDataset): boolean;
begin
   if (not aMds.active) or (aMds.RecordCount<=0) then
      begin
         Result:=false;
         exit;
      end;
   try
      ff_CustomerID := Trim(aMds.FieldByName('CustomerID').AsString);
      flag_CustomerID:=(not aMds.FieldByName('CustomerID').IsNull);
      ff_CompanyName := Trim(aMds.FieldByName('CompanyName').AsString);
      flag_CompanyName:=(not aMds.FieldByName('CompanyName').IsNull);
      ff_ContactName := Trim(aMds.FieldByName('ContactName').AsString);
      flag_ContactName:=(not aMds.FieldByName('ContactName').IsNull);
      ff_ContactTitle := Trim(aMds.FieldByName('ContactTitle').AsString);
      flag_ContactTitle:=(not aMds.FieldByName('ContactTitle').IsNull);
      ff_Address := Trim(aMds.FieldByName('Address').AsString);
      flag_Address:=(not aMds.FieldByName('Address').IsNull);
      ff_City := Trim(aMds.FieldByName('City').AsString);
      flag_City:=(not aMds.FieldByName('City').IsNull);
      ff_Region := Trim(aMds.FieldByName('Region').AsString);
      flag_Region:=(not aMds.FieldByName('Region').IsNull);
      ff_PostalCode := Trim(aMds.FieldByName('PostalCode').AsString);
      flag_PostalCode:=(not aMds.FieldByName('PostalCode').IsNull);
      ff_Country := Trim(aMds.FieldByName('Country').AsString);
      flag_Country:=(not aMds.FieldByName('Country').IsNull);
      ff_Phone := Trim(aMds.FieldByName('Phone').AsString);
      flag_Phone:=(not aMds.FieldByName('Phone').IsNull);
      ff_Fax := Trim(aMds.FieldByName('Fax').AsString);
      flag_Fax:=(not aMds.FieldByName('Fax').IsNull);
      ff_Peoples := aMds.FieldByName('Peoples').AsInteger;
      flag_Peoples:=(not aMds.FieldByName('Peoples').IsNull);
      result:=true;
   except
      result:=false;
   end;
end;
//
// 将对象转换到Mds的当前记录...
function TCustomers.SaveToMds(Mds: TMemDataset): Boolean;
begin
   try
     Mds.edit;
     if flag_CustomerID then
        Mds.FieldValues['CustomerID']:=ff_CustomerID;
     if flag_CompanyName then
        Mds.FieldValues['CompanyName']:=ff_CompanyName;
     if flag_ContactName then
        Mds.FieldValues['ContactName']:=ff_ContactName;
     if flag_ContactTitle then
        Mds.FieldValues['ContactTitle']:=ff_ContactTitle;
     if flag_Address then
        Mds.FieldValues['Address']:=ff_Address;
     if flag_City then
        Mds.FieldValues['City']:=ff_City;
     if flag_Region then
        Mds.FieldValues['Region']:=ff_Region;
     if flag_PostalCode then
        Mds.FieldValues['PostalCode']:=ff_PostalCode;
     if flag_Country then
        Mds.FieldValues['Country']:=ff_Country;
     if flag_Phone then
        Mds.FieldValues['Phone']:=ff_Phone;
     if flag_Fax then
        Mds.FieldValues['Fax']:=ff_Fax;
     if flag_Peoples then
        Mds.FieldValues['Peoples']:=ff_Peoples;
     Mds.post;
     result:=true;
   except
     result:=false;
   end;
end;
//
// 从远程数据库中读一个记录,并转换成对象实例...
function TCustomers.ReadFromDB(DBA: TLazAccessor; Condition: String): boolean;
var
  SqlCommand: String;
  Mds: TMemDataset;
begin
  Mds:=TMemDataset.Create(nil);
  if Condition='' then
     SqlCommand:='SELECT * FROM Customers'
  else
     SqlCommand := 'SELECT * FROM Customers WHERE '+condition;
  if not DBA.ReadDataset(SqlCommand,Mds) then
     begin
       Mds.Free;
       result:=false;
       exit;
     end;
  Result:=ReadFromMds(Mds);
  Mds.Free;
end;
//
// 将对象实例的属性写入到远程数据库记录...
function TCustomers.InsertToDB(DBA: TLazAccessor): boolean;
var
  Mds: TMemDataset;
begin
  Mds:=CreateMds;
  try
     Mds.Append;
     if flag_CustomerID then
        Mds.FieldValues['CustomerID']:=ff_CustomerID;
     if flag_CompanyName then
        Mds.FieldValues['CompanyName']:=ff_CompanyName;
     if flag_ContactName then
        Mds.FieldValues['ContactName']:=ff_ContactName;
     if flag_ContactTitle then
        Mds.FieldValues['ContactTitle']:=ff_ContactTitle;
     if flag_Address then
        Mds.FieldValues['Address']:=ff_Address;
     if flag_City then
        Mds.FieldValues['City']:=ff_City;
     if flag_Region then
        Mds.FieldValues['Region']:=ff_Region;
     if flag_PostalCode then
        Mds.FieldValues['PostalCode']:=ff_PostalCode;
     if flag_Country then
        Mds.FieldValues['Country']:=ff_Country;
     if flag_Phone then
        Mds.FieldValues['Phone']:=ff_Phone;
     if flag_Fax then
        Mds.FieldValues['Fax']:=ff_Fax;
     if flag_Peoples then
        Mds.FieldValues['Peoples']:=ff_Peoples;
     Mds.Post;
  except
     Mds.Free;
     Result:=false;
     exit;
  end;
  Result:=DBA.AppendRecord('Customers',Mds);
  Mds.Free;
end;
//
// 将对象实例的属性更新到数据库记录...
function TCustomers.UpdateToDB(DBA: TLazAccessor; Condition: String): boolean;
var
  Mds: TMemDataset;
begin
  Mds:=CreateMds;
  try
     Mds.Append;
     if flag_CustomerID then
        Mds.FieldValues['CustomerID']:=ff_CustomerID;
     if flag_CompanyName then
        Mds.FieldValues['CompanyName']:=ff_CompanyName;
     if flag_ContactName then
        Mds.FieldValues['ContactName']:=ff_ContactName;
     if flag_ContactTitle then
        Mds.FieldValues['ContactTitle']:=ff_ContactTitle;
     if flag_Address then
        Mds.FieldValues['Address']:=ff_Address;
     if flag_City then
        Mds.FieldValues['City']:=ff_City;
     if flag_Region then
        Mds.FieldValues['Region']:=ff_Region;
     if flag_PostalCode then
        Mds.FieldValues['PostalCode']:=ff_PostalCode;
     if flag_Country then
        Mds.FieldValues['Country']:=ff_Country;
     if flag_Phone then
        Mds.FieldValues['Phone']:=ff_Phone;
     if flag_Fax then
        Mds.FieldValues['Fax']:=ff_Fax;
     if flag_Peoples then
        Mds.FieldValues['Peoples']:=ff_Peoples;
     Mds.Post;
  except
     Mds.Free;
     Result:=false;
     exit;
  end;
  Result:=DBA.UpdateRecord('Customers',Condition,Mds);
  Mds.Free;
end;
//
// 删除对象实例所对应的数据库记录...
function TCustomers.DeleteFromDB(DBA: TLazAccessor; Condition: String): boolean;
var
   SqlCommand,tmpstr: String;
begin
  if Condition='' then
     SqlCommand:='DELETE FROM Customers'
  else
     SqlCommand:='DELETE FROM Customers WHERE '+condition;
  result:=DBA.ExecuteSQL(SqlCommand,false,tmpstr);
end;
//
// 判定属性是否null的函数...
function TCustomers.PropIsNull(PropName: string): boolean;
begin
  result:=true;
  if StrIComp(PChar(PropName),PChar('CustomerID'))=0 then
     begin
        result:=not flag_CustomerID;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('CompanyName'))=0 then
     begin
        result:=not flag_CompanyName;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('ContactName'))=0 then
     begin
        result:=not flag_ContactName;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('ContactTitle'))=0 then
     begin
        result:=not flag_ContactTitle;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Address'))=0 then
     begin
        result:=not flag_Address;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('City'))=0 then
     begin
        result:=not flag_City;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Region'))=0 then
     begin
        result:=not flag_Region;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('PostalCode'))=0 then
     begin
        result:=not flag_PostalCode;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Country'))=0 then
     begin
        result:=not flag_Country;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Phone'))=0 then
     begin
        result:=not flag_Phone;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Fax'))=0 then
     begin
        result:=not flag_Fax;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Peoples'))=0 then
     begin
        result:=not flag_Peoples;
        exit;
     end;
end;
//
// 设置某属性的值为null...
function TCustomers.SetPropNull(PropName: string): boolean;
begin
  result:=false;
  if StrIComp(PChar(PropName),PChar('CustomerID'))=0 then
     begin
        ff_CustomerID:='';
        flag_CustomerID:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('CompanyName'))=0 then
     begin
        ff_CompanyName:='';
        flag_CompanyName:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('ContactName'))=0 then
     begin
        ff_ContactName:='';
        flag_ContactName:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('ContactTitle'))=0 then
     begin
        ff_ContactTitle:='';
        flag_ContactTitle:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Address'))=0 then
     begin
        ff_Address:='';
        flag_Address:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('City'))=0 then
     begin
        ff_City:='';
        flag_City:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Region'))=0 then
     begin
        ff_Region:='';
        flag_Region:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('PostalCode'))=0 then
     begin
        ff_PostalCode:='';
        flag_PostalCode:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Country'))=0 then
     begin
        ff_Country:='';
        flag_Country:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Phone'))=0 then
     begin
        ff_Phone:='';
        flag_Phone:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Fax'))=0 then
     begin
        ff_Fax:='';
        flag_Fax:=false;
        result:=true;
        exit;
     end;
  if StrIComp(PChar(PropName),PChar('Peoples'))=0 then
     begin
        ff_Peoples:=0;
        flag_Peoples:=false;
        result:=true;
        exit;
     end;
end;

{ TCustomersList }
//
// 清除列表...
procedure TCustomersList.Clear;  
var
   i: integer;
begin
   for i:=0 to Count-1 do
      TCustomers(items[i]).free;
   inherited clear;
end;
//
// 从远程数据表读取记录并转换为列表对象实例...
function TCustomersList.ReadFromDB(DBA: TLazAccessor; Condition: String; Orderby: String):Boolean;
var
  SqlCommand: String;
  Mds: TMemDataset;
  TmpObj: TCustomers;
begin
  Clear;
  Mds:=TMemDataset.Create(nil);
  if Condition='' then
     begin
        SqlCommand := 'SELECT '
                    +'[CustomerID],'
                    +'[CompanyName],'
                    +'[ContactName],'
                    +'[ContactTitle],'
                    +'[Address],'
                    +'[City],'
                    +'[Region],'
                    +'[PostalCode],'
                    +'[Country],'
                    +'[Phone],'
                    +'[Fax],'
                    +'[Peoples]'
                    +' FROM Customers'
     end
  else
     begin
        SqlCommand := 'SELECT '
                    +'[CustomerID],'
                    +'[CompanyName],'
                    +'[ContactName],'
                    +'[ContactTitle],'
                    +'[Address],'
                    +'[City],'
                    +'[Region],'
                    +'[PostalCode],'
                    +'[Country],'
                    +'[Phone],'
                    +'[Fax],'
                    +'[Peoples]'
                    +' FROM Customers WHERE '+Condition;
     end;
  if Orderby<>'' then
     SqlCommand:=SqlCommand+' ORDER BY '+Orderby;
  if not DBA.ReadDataset(SqlCommand,Mds) then
     begin
        Result:=false;
        Mds.Free;
        exit;
     end;
  Mds.First;
  while not Mds.Eof do
     begin
        TmpObj := TCustomers.Create;
        TmpObj.ReadFromMDS(Mds);
        Add(TmpObj);
        Mds.Next;
     end;
  Mds.Free;
  result:=true;
end;
//
// 将本地Mds中的记录集转换为列表对象实例...
function TCustomersList.ReadFromMDS(Mds: TMemDataset): boolean;
var
  TmpObj: TCustomers;
begin
  Clear;
  Mds.First;
  while not Mds.Eof do
     begin
        TmpObj := TCustomers.Create;
        TmpObj.ReadFromMDS(Mds);
        Add(TmpObj);
        Mds.Next;
     end;
  Result:=true;
end;
//
// 将列表对象包含的一批对象保存为Mds中的若干记录...
function TCustomersList.SaveToMds(var Mds: TMemDataset): boolean;
var
  TmpObj: TCustomers;
  i: integer;
begin
  Mds:=CreateMds;
  result:=true;
  for i:=0 to Self.Count-1 do
     begin
        TmpObj:=TCustomers(items[i]);
        try
           Mds.Append;
           if TmpObj.CustomerID_Updated then
              Mds.FieldValues['CustomerID']:=TmpObj.f_CustomerID;
           if TmpObj.CompanyName_Updated then
              Mds.FieldValues['CompanyName']:=TmpObj.f_CompanyName;
           if TmpObj.ContactName_Updated then
              Mds.FieldValues['ContactName']:=TmpObj.f_ContactName;
           if TmpObj.ContactTitle_Updated then
              Mds.FieldValues['ContactTitle']:=TmpObj.f_ContactTitle;
           if TmpObj.Address_Updated then
              Mds.FieldValues['Address']:=TmpObj.f_Address;
           if TmpObj.City_Updated then
              Mds.FieldValues['City']:=TmpObj.f_City;
           if TmpObj.Region_Updated then
              Mds.FieldValues['Region']:=TmpObj.f_Region;
           if TmpObj.PostalCode_Updated then
              Mds.FieldValues['PostalCode']:=TmpObj.f_PostalCode;
           if TmpObj.Country_Updated then
              Mds.FieldValues['Country']:=TmpObj.f_Country;
           if TmpObj.Phone_Updated then
              Mds.FieldValues['Phone']:=TmpObj.f_Phone;
           if TmpObj.Fax_Updated then
              Mds.FieldValues['Fax']:=TmpObj.f_Fax;
           if TmpObj.Peoples_Updated then
              Mds.FieldValues['Peoples']:=TmpObj.f_Peoples;
           Mds.Post;
        except
           result:=false;
           break;
        end;
     end;
end;
//
// 将对象实例的属性写入到远程数据库记录...
function TCustomersList.InsertToDB(DBA: TLazAccessor): boolean;
var
  Mds: TMemDataset;
begin
  Result:=SaveToMds(Mds);
  if Result then
     Result:=DBA.WriteDataset(Mds,'Customers');
  FreeAndNil(Mds);
end;
//
// 将对象实例的属性更新到数据库记录...
function TCustomersList.UpdateToDB(DBA: TLazAccessor; Condition: String): boolean;
var
  Mds: TMemDataset;
begin
  Result:=SaveToMds(Mds);
  if Result then
     Result:=DBA.WriteDataset(Mds,'Customers',Condition);
  FreeAndNil(Mds);
end;
//
// 删除对象实例所对应的数据库记录...
function TCustomersList.DeleteFromDB(DBA: TLazAccessor; Condition: String): boolean;
var
   SqlCommand,tmpstr: String;
begin
  SqlCommand:='DELETE FROM Customers WHERE '+condition;
  result:=DBA.ExecuteSQL(SqlCommand,false,tmpstr);
end;
//
// 将列表对象包含的一批对象保存到外部文件中...
function TCustomersList.SaveToFile(FileName: String): boolean;
var
  Mds: TMemDataset;
  TmpObj: TCustomers;
  i: integer;
begin
  Mds:=CreateMds;
  result:=true;
  for i:=0 to Self.Count-1 do
     begin
        TmpObj:=TCustomers(items[i]);
        try
           Mds.Append;
           if TmpObj.CustomerID_Updated then
              Mds.FieldValues['CustomerID']:=TmpObj.f_CustomerID;
           if TmpObj.CompanyName_Updated then
              Mds.FieldValues['CompanyName']:=TmpObj.f_CompanyName;
           if TmpObj.ContactName_Updated then
              Mds.FieldValues['ContactName']:=TmpObj.f_ContactName;
           if TmpObj.ContactTitle_Updated then
              Mds.FieldValues['ContactTitle']:=TmpObj.f_ContactTitle;
           if TmpObj.Address_Updated then
              Mds.FieldValues['Address']:=TmpObj.f_Address;
           if TmpObj.City_Updated then
              Mds.FieldValues['City']:=TmpObj.f_City;
           if TmpObj.Region_Updated then
              Mds.FieldValues['Region']:=TmpObj.f_Region;
           if TmpObj.PostalCode_Updated then
              Mds.FieldValues['PostalCode']:=TmpObj.f_PostalCode;
           if TmpObj.Country_Updated then
              Mds.FieldValues['Country']:=TmpObj.f_Country;
           if TmpObj.Phone_Updated then
              Mds.FieldValues['Phone']:=TmpObj.f_Phone;
           if TmpObj.Fax_Updated then
              Mds.FieldValues['Fax']:=TmpObj.f_Fax;
           if TmpObj.Peoples_Updated then
              Mds.FieldValues['Peoples']:=TmpObj.f_Peoples;
           Mds.Post;
        except
           result:=false;
           break;
        end;
     end;
  if result then
     begin
        try
           Mds.SaveToFile(String(FileName));
        except
           result:=false;
        end;
     end;
  Mds.Free;
end;
//
// 从文件中装入数据,转换为列表对象中的一系列对象...
function TCustomersList.LoadFromFile(FileName: String): boolean;
var
  Mds: TMemDataset;
  TmpObj: TCustomers;
begin
  Clear;
  Mds:=TMemDataset.Create(nil);
  try
     Mds.LoadFromFile(String(FileName));
     result:=Mds.Active;
  except
     result:=false;
  end;
  if not result then
     begin
        Mds.Free;
        exit;
     end;
  Mds.First;
  while not Mds.Eof do
     begin
        TmpObj := TCustomers.Create;
        TmpObj.ReadFromMDS(Mds);
        Add(TmpObj);
        Mds.Next;
     end;
  Mds.Free;
end;
//
// 保存列表对象中所含数据到内存流对象...
function TCustomersList.SaveToStream(aStream: TMemoryStream): boolean;
var
  Mds: TMemDataset;
  TmpObj: TCustomers;
  i: integer;
begin
  Mds:=CreateMds;
  result:=true;
  for i:=0 to Self.Count-1 do
     begin
        TmpObj:=TCustomers(items[i]);
        try
           Mds.Append;
           if TmpObj.CustomerID_Updated then
              Mds.FieldValues['CustomerID']:=TmpObj.f_CustomerID;
           if TmpObj.CompanyName_Updated then
              Mds.FieldValues['CompanyName']:=TmpObj.f_CompanyName;
           if TmpObj.ContactName_Updated then
              Mds.FieldValues['ContactName']:=TmpObj.f_ContactName;
           if TmpObj.ContactTitle_Updated then
              Mds.FieldValues['ContactTitle']:=TmpObj.f_ContactTitle;
           if TmpObj.Address_Updated then
              Mds.FieldValues['Address']:=TmpObj.f_Address;
           if TmpObj.City_Updated then
              Mds.FieldValues['City']:=TmpObj.f_City;
           if TmpObj.Region_Updated then
              Mds.FieldValues['Region']:=TmpObj.f_Region;
           if TmpObj.PostalCode_Updated then
              Mds.FieldValues['PostalCode']:=TmpObj.f_PostalCode;
           if TmpObj.Country_Updated then
              Mds.FieldValues['Country']:=TmpObj.f_Country;
           if TmpObj.Phone_Updated then
              Mds.FieldValues['Phone']:=TmpObj.f_Phone;
           if TmpObj.Fax_Updated then
              Mds.FieldValues['Fax']:=TmpObj.f_Fax;
           if TmpObj.Peoples_Updated then
              Mds.FieldValues['Peoples']:=TmpObj.f_Peoples;
           Mds.Post;
        except
           result:=false;
           break;
        end;
     end;
  if result then
     begin
        try
           aStream.Clear;
           Mds.SaveToStream(aStream);
        except
           result:=false;
        end;
     end;
  Mds.Free;
end;
//
// 从内存流对象装入数据到列表对象中...
function TCustomersList.LoadFromStream(aStream: TMemoryStream): boolean;
var
  Mds: TMemDataset;
  TmpObj: TCustomers;
begin
  Clear;
  Mds:=TMemDataset.Create(nil);
  try
     aStream.Position:=0;
     Mds.LoadFromStream(aStream);
     result:=Mds.Active;
  except
     result:=false;
  end;
  if not result then
     begin
        Mds.Free;
        exit;
     end;
  Mds.First;
  while not Mds.Eof do
     begin
        TmpObj := TCustomers.Create;
        TmpObj.ReadFromMDS(Mds);
        Add(TmpObj);
        Mds.Next;
     end;
  Mds.Free;
end;
end.

回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2013-8-13 09:37:19 | 显示全部楼层
5、我们再来看基于实体类的数据表增删改的编程示例:
//
// 主列表单元。。。
unit main;
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  StdCtrls, Entity_Customers, LazConnection, LazAccessor, edit, LCLType;
type
  { TMainForm }
  TMainForm = class(TForm)
     Button1: TButton;
     Button2: TButton;
     Button3: TButton;
     Button4: TButton;
     Button5: TButton;
     dba: TLazAccessor;
     ImageList1: TImageList;
     LazConn: TLazConnection;
     ListView1: TListView;
     StatusBar1: TStatusBar;
     procedure Button1Click(Sender: TObject);
     procedure Button2Click(Sender: TObject);
     procedure Button3Click(Sender: TObject);
     procedure Button4Click(Sender: TObject);
     procedure Button5Click(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure ListView1DblClick(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
     custlist: TCustomersList;
  end;
var
  MainForm: TMainForm;
implementation
{$R *.lfm}
{ TMainForm }
procedure TMainForm.FormCreate(Sender: TObject);
begin
  if lazconn.Connect then
     begin
        statusbar1.panels[0].Text:='连接服务器成功,请继续测试!';
        Button1Click(nil);
     end
  else
    statusbar1.panels[0].Text:='连接服务器成功,无法继续测试!';
end;
//
// 双击,打开修改...
procedure TMainForm.ListView1DblClick(Sender: TObject);
begin
  if listview1.Selected=nil then
     exit;
  Button3Click(nil);
end;
//
// 刷新...
procedure TMainForm.Button1Click(Sender: TObject);
var
   i: integer;
   cust: TCustomers;
begin
   custlist:=TCustomersList.Create;
   if custlist.ReadFromDB(dba,'','') then
      begin
         statusbar1.panels[0].Text:='读取列表成功!';
         listview1.Items.BeginUpdate;
         listview1.Items.Clear;
         for i:=0 to custlist.Count-1 do
            begin
               cust:=TCustomers(custlist.Items[i]);
               with listview1.Items.Add do
                  begin
                     caption:=cust.f_CustomerID;
                     subitems.Add(cust.f_ContactName);
                     subitems.Add(cust.f_CompanyName);
                     subitems.Add(cust.f_Phone);
                     subitems.Add(cust.f_Fax);
                     imageindex:=0;
                  end;
            end;
         ListView1.Items.EndUpdate;
      end
   else
     statusbar1.panels[0].Text:='读列表失败,Error='+dba.LastError;
end;
//
// 新增...
procedure TMainForm.Button2Click(Sender: TObject);
begin
   editform:=TEditForm.create(nil);
   editform.mode:=1;
   editform.showmodal;
   if editform.execute then
      begin
         editform.customer.InsertToDB(dba);
         custlist.Add(editform.customer);
         with listview1.Items.Add do
            begin
               caption:=editform.customer.f_CustomerID;
               subitems.Add(editform.customer.f_ContactName);
               subitems.Add(editform.customer.f_CompanyName);
               subitems.Add(editform.customer.f_Phone);
               subitems.Add(editform.customer.f_Fax);
               imageindex:=0;
            end;
      end;
   editform.free;
end;
//
// 修改...
procedure TMainForm.Button3Click(Sender: TObject);
begin
   if listview1.Selected=nil then
      begin
         showmessage('请先选择需要修改的客户记录!');
         exit;
      end;
   editform:=TEditForm.create(nil);
   editform.mode:=2;
   editform.Customer:=TCustomers(custlist.Items[listview1.Selected.Index]);
   editform.showmodal;
   if editform.execute then
      begin
         editform.customer.UpdateToDB(dba,'CustomerId='''+editform.customer.f_CustomerID+'''');
         with listview1.selected do
            begin
               subitems[0]:=editform.customer.f_ContactName;
               subitems[1]:=editform.customer.f_CompanyName;
               subitems[2]:=editform.customer.f_Phone;
               subitems[3]:=editform.customer.f_Fax;
            end;
      end;
   editform.free;
end;
//
// 删除...
procedure TMainForm.Button4Click(Sender: TObject);
var
   customer: TCustomers;
begin
   if listview1.Selected=nil then
      begin
         showmessage('请先选择需要修改的客户记录!');
         exit;
      end;
   if application.MessageBox('是否确认删除当前选中的客户记录?','删除确认',mb_yesno+mb_iconquestion)<>idyes then
      exit;
   customer:=TCustomers(custlist.Items[listview1.Selected.Index]);
   customer.DeleteFromDB(dba,'customerid='''+customer.f_CustomerID+'''');
   customer.Free;
   custlist.Delete(listview1.Selected.Index);
   listview1.Selected.delete;
end;
procedure TMainForm.Button5Click(Sender: TObject);
begin
   if assigned(custlist) then
      custlist.Free;
   lazconn.Disconnect;
   close;
end;
end.

//
// 记录编辑单元。。。
unit edit;
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, Entity_Customers;
type
  { TEditForm }
  TEditForm = class(TForm)
     Bevel1: TBevel;
     Button1: TButton;
     Button2: TButton;
     Edit1: TEdit;
     Edit2: TEdit;
     Edit3: TEdit;
     Edit4: TEdit;
     Edit5: TEdit;
     Label1: TLabel;
     Label2: TLabel;
     Label3: TLabel;
     Label4: TLabel;
     Label5: TLabel;
     Label6: TLabel;
     Label7: TLabel;
     Label8: TLabel;
     procedure Button1Click(Sender: TObject);
     procedure Button2Click(Sender: TObject);
     procedure FormShow(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
     Customer: TCustomers;
     mode: integer;
     execute: boolean;
  end;
var
  EditForm: TEditForm;
implementation
{$R *.lfm}
{ TEditForm }
procedure TEditForm.Button2Click(Sender: TObject);
begin
   execute:=false;
   close;
end;
procedure TEditForm.Button1Click(Sender: TObject);
begin
   if (trim(edit1.text)='') or (trim(edit2.text)='') or (trim(edit3.text)='') then
      begin
         ShowMessage('对不起,带*号的必须填写,请重新输入!');
         exit;
      end;
   if mode=1 then
      customer:=TCustomers.Create;
   customer.f_CustomerID:=trim(edit1.text);
   customer.f_ContactName:=trim(edit2.text);
   customer.f_CompanyName:=trim(edit3.text);
   customer.f_Phone:=trim(edit4.text);
   customer.f_Fax:=trim(edit5.text);
   execute:=true;
   close;
end;
procedure TEditForm.FormShow(Sender: TObject);
begin
//
// 新增...
   if mode=1 then
      begin
         edit1.text:='';
         edit2.text:='';
         edit3.text:='';
         edit4.text:='';
         edit5.text:='';
         edit1.Enabled:=true;
      end
//
// 修改...
   else
      begin
         edit1.text:=customer.f_CustomerID;
         edit2.text:=customer.f_ContactName;
         edit3.text:=customer.f_CompanyName;
         edit4.text:=customer.f_Phone;
         edit5.text:=customer.f_Fax;
         edit1.Enabled:=false;
      end;
end;
end.


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册(注册审核可向QQ群索取)

x
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2013-8-13 09:43:56 | 显示全部楼层
6、结语:
    从上面的示例代码可以看出,尽管是在三层架构模式下,但由于采用了ORM  实体类封装,使得远程交互的细节不再与应用程序员直接发生关系,程序编写起来就更加简单;而且,由于应用接口一致,也更适合团队协作开发。

补充:  QuickBurro下载地址: http://www.quickburro.com/download/qbcn.rar

按如下三步上手:
     1、下载解包、将 server  复制到你的应用服务器上,运行burrocontrol密码空,再点“启动”,最后配置一下你的数据库
     2、将 LazSDK下的开发包安装到你的 Lazarus中,再看资料和 Demo,熟悉控件用法
     3、开发你的应用程序、发布
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2013-9-9 14:04:28 | 显示全部楼层
你好,驴它爹,再见。。。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2014-4-25 08:15:27 | 显示全部楼层
不错,很多年前也写过类似的工具,不过是为struts生成数据库对象的
回复 支持 反对

使用道具 举报

*滑块验证:

本版积分规则

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

GMT+8, 2025-5-2 20:59 , Processed in 0.031053 second(s), 9 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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