DELPHI 利用RTTL实现DAO模式下属性的动态设置及精确生成SQL语句

从一个简单的例子开始。创建一个USERDAO

    

userDAO := TUserDAO(daofact.getDAO('TUserDAO', getpoolWapper)); 

daofact

,是DAO

工厂, 'TUserDAO',

客户可以不用知道DAO

是怎么创建的,隐藏实现细节。getpoolWapper, 

是注入的一个数据库连接。(这里可以用数据库连接池实现)具体请参考我前一篇文章《用Dunit

测试 BPL

方式实现的数据库连接池实战开发》。


    



function TDAOFactory.getDAO(const daoClassName: String; tmpIConnWrap: IConnPoolWrapper): TObject;

var

  

tmpPer: TPersistent;

begin

  

if FindClass(daoClassName) <> nil then

  

begin

    

tmpPer := TPersistentClass(FindClass(daoClassName)).Create;

    

Result := tmpPer;

 

    

Supports(tmpPer, StringToGUID('{C98D6EC3-86E8-4274-A812-FA73C6B07B4F}'), IBasDAO);

    

try

      

IBasDAO.initializeDAO(tmpIConnWrap);

    

except

      

IBasDAO := nil;

    

end;

  

end;

  



end;

    



由一BASDAO

, 取得注入的数据库连接。注:所有数据操作方面都应该是由DAO

层面的。


constructor TBasicDAO.Create(tmpIConnWrap: IConnPoolWrapper);

begin

  

inherited Create;

  

tmpPer := TDataPersistent.Create(tmpIConnWrap);

  

IDataPer := IDataPersistent(tmpPer);

  

DAOAdapter := TDAOAdapter.Create(IDataPer);

end;

  

TDataPersistent

类具体包装了数据库操作部分, 它的接口入下:


  

IDataPersistent = interface(IInterface)

    

['{16437543-63E7-41F1-914B-0E3AE8A3A5CC}']

    

procedure BeginTrans;

    

procedure CommitTrans;

    

procedure RollBackTrans;

    

function SelectDataSet(const SelectStr: String): TDataSet;

    

function InsertDataSet(const InsertStr: String): Boolean;

    

function UpdateDataSet(const UpdateStr: String): Boolean;

    

function DeleteDataSet(const DeleteStr: String): Boolean;

   

end;

 

 IBasicDAO = interface(IInterface)

    

['{C98D6EC3-86E8-4274-A812-FA73C6B07B4F}']

    

procedure initializeDAO(tmpIConnWrap: IConnPoolWrapper);

    

function selectTOList(pTO: TObject; startRow: Integer; howManyRows: Integer): TObjectList; overload;

    

function selectTOList(startRow: Integer; howManyRows: Integer): TObjectList; overload;

  

end;

 

   

IUserDAO = interface(IBasicDAO)

    

['{91FF66E5-F230-4AC8-B0AB-1E1A2E741A42}']

    

function insertDAO(pUserTO: TUserTO): Boolean;

    

function updateDAO(pUserTO: TUserTO): Boolean;

    

function deleteDAO(pUserTO: TUserTO): Boolean;

  

end;

 

    



所有DAOinsert, update, delete 

操作都

委托

给了TDAOAdapter

实现。TDAOAdapter

利用rttl

技术对TO

属性存取, 自动生成了 insert ,update, delete

语句,及属性

动态

设置。


利用这一点,使得所有的TO

都非常方便的

自动存取

 

constructor TUserDAO.Create(tmpIConnWrap: IConnPoolWrapper);

begin

  

inherited Create(tmpIConnWrap);

end;

 

function TUserDAO.insertDAO(pUserTO: TUserTO): Boolean;

begin

  

Result := FDAOAdapter.InsertDAO(pUserTO, 'Customer');

end;

 

function TUserDAO.updateDAO(pUserTO: TUserTO): Boolean;

begin

  

Result := FDAOAdapter.updateDAO(pUserTO, 'Customer');

end;

 

function TUserDAO.deleteDAO(pUserTO: TUserTO): Boolean;

begin

  

Result := FDAOAdapter.deleteDAO(pUserTO, 'Customer');

end;

 

function TUserDAO.selectTOList(pTO: TObject; startRow: Integer; howManyRows: Integer): TObjectList;

var

  

tmpTable: String;

begin

  

tmpTable := 'Customer';

  

Result := FDAOAdapter.selectTOList(tmpTable, pTO, startRow, howManyRows);

end;

 

从上面的代码看出

委托

给了FDAOAdapter, FDAOAdapter

的具体实现如下:


 

function TDAOAdapter.getSearchSQLString(Const pTO: TObject; tmpTbname: String): String;

var

  

i: Integer;

  

tmpSQL, tmpFid: String;

  

tmpPropList: TMPropList;

begin

  

tmpSQL := 'select ';

  

tmpPropList := TDataTransferObject(pTO).FPropList;

 

  

for i:=1 to tmpPropList.PropCount-1 do

  

begin

    

tmpSQL :=  

tmpSQL + GetFldName(tmpPropList.PropNames[i]) +','

  

end;

  

tmpSQL := Copy(tmpSQL,0, length(tmpSQL)-1);

  

tmpSQL := tmpSQL +' FROM '+tmpTbname+' where 1=1';

 

  

for i:=1 to tmpPropList.PropCount-1 do

  

begin

    

case tmpPropList.Props[i]^.PropType^.Kind of

      

tkInteger:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+IntToStr( GetOrdProp(pTO, tmpPropList.Props[i]) );

      

tkInt64:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+IntToStr( GetInt64Prop(pTO, tmpPropList.Props[i]) );

      

tkChar, tkLString, tkString:

        

if not (Trim( GetStrProp(pTO, tmpPropList.Props[i]) ) = '') then

          

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+QuotedStr( GetStrProp(pTO, tmpPropList.Props[i]) );

      

tkSet:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+QuotedStr( GetSetProp(pTO, tmpPropList.Props[i]) );

      

tkEnumeration:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+QuotedStr( GetEnumProp(pTO, tmpPropList.Props[i]) );

      

tkFloat:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+FloatToStr( GetFloatProp(pTO, tmpPropList.Props[i]) );

      

tkWChar, tkWString:

        

if not (Trim(GetWideStrProp(pTO, tmpPropList.Props[i])) = '') then

          

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+QuotedStr( GetWideStrProp(pTO, tmpPropList.Props[i]) );

    

end;

 

  

end;

  

Result := tmpSQL;

 

end;

 

 

 

 

function TDAOAdapter.getDeleteSQLString(Const pTO: TObject; tmpTbname: String): String;

var

  

i: Integer;

  

tmpSQL: String;

  

tmpPropList: TMPropList;

begin

  

tmpSQL := 'Delete '+tmpTbname+' where 1=1 ';

  

tmpPropList := TDataTransferObject(pTO).FPropList;

 

  

for i:=1 to tmpPropList.PropCount-1 do

  

begin

    

case tmpPropList.Props[i]^.PropType^.Kind of

      

tkInteger:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+IntToStr( GetOrdProp(pTO, tmpPropList.Props[i]) );

      

tkInt64:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+IntToStr( GetInt64Prop(pTO, tmpPropList.Props[i]) );

      

tkChar, tkLString, tkString:

        

if not (Trim( GetStrProp(pTO, tmpPropList.Props[i]) ) = '') then

          

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+QuotedStr( GetStrProp(pTO, tmpPropList.Props[i]) );

      

tkSet:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+QuotedStr( GetSetProp(pTO, tmpPropList.Props[i]) );

      

tkEnumeration:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+QuotedStr( GetEnumProp(pTO, tmpPropList.Props[i]) );

      

tkFloat:

        

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+FloatToStr( GetFloatProp(pTO, tmpPropList.Props[i]) );

      

tkWChar, tkWString:

        

if not (Trim(GetWideStrProp(pTO, tmpPropList.Props[i])) = '') then

          

tmpSQL := tmpSQL +' and '+ GetFldName(tmpPropList.PropNames[i])+'='+QuotedStr( GetWideStrProp(pTO, tmpPropList.Props[i]) );

    

end;

 

  

end;

 

  

Result := tmpSQL;

end;

 

  



客户端的数据由TDAOAdapter

返回.



function TDAOAdapter.executeSeach(Const pTO: TObject; searchStr: String; startRow: Integer; howManyRows: Integer): TObjectList;

begin

  

if not assigned(rowSetList) then

    

rowSetList := TRowSetWrapperList.Create;

 

  

Result := rowSetList.CreateDTOObject(pTO.ClassName, DataPer.SelectDataSet(searchStr));

end;

 

TRowSetWrapperList 

实现了tdataset(

动态生成clientdateset)

的导航.



getindex; next ,last

等方法。


 

 

客户端的代码如下:


  

tmpList: TObjectList;

  

userTO := TUserTo.Create;

 

  

//

查找所有yhh'01'TO

返回TObjectList;



  

userTo.yhh := '01';

  

tmpList := iInter.selectTOList(userTO, 0, 1000);

 

  

for i:=0 to tmpList.Count-1 do

  

begin

    

tmpTO := TUserTo(tmpList.Items[i]);

    

ShowMESSAGE(TMPtO.yhm);

  

end;

 

 

新增如下:


 

 

function TDAOAdapter.getSearchSQLString(Const pTO: TDataTransferObject): String;

var

  

i,j: Integer;

  

tmpSQL, tmpFid, tmpTbname: String;

  

tmpPropList, tmpProp2: TMPropList;

  

tmpObj: TObject;

  

tmpInfo: TTypeInfo;

begin

  

tmpSQL := 'select ';

 

  

if not pTO.isDetail then

  

begin

    

//

单表情况:



    

tmpPropList := pTO.FPropList;

    

tmpTbname := pTO.tbName;

 

    

for i:=0 to tmpPropList.PropCount-1 do

    

begin

      

if GetFldName(tmpPropList.PropNames[i])<>'' then

        

tmpSQL :=  

tmpSQL + GetFldName(tmpPropList.PropNames[i]) +','

    

end;

    

tmpSQL := Copy(tmpSQL,0, length(tmpSQL)-1);

    

tmpSQL := tmpSQL +' FROM '+tmpTbname+' where 1=1';

    

Result := tmpSQL;

  

end

  

else

  

begin

    

//

明细表情况:


    

tmpPropList := pTO.FPropList;

    

tmpSQL := 'select ';

    

for i:=0 to tmpPropList.PropCount-1 do

    

begin

       

case tmpPropList.Props[i]^.PropType^.Kind of

         

tkClass:

           

begin

             

tmpObj := GetObjectProp(pTO, tmpPropList.Props[i]);

             

tmpProp2 := TDataTransferObject(tmpObj).FPropList;

             

tmpTbname := TDataTransferObject(tmpObj).tbName;

 

             

for j:=0 to tmpProp2.PropCount-1 do

             

begin

               

if GetFldName(tmpProp2.PropNames[j])<>'' then

                 

tmpSQL :=  

tmpSQL + tmpTbname +'.'+GetFldName(tmpProp2.PropNames[j]) +','

             

end;

           

end;

       

end;

 

    

end;

 

    

tmpSQL := Copy(tmpSQL,0, length(tmpSQL)-1);

    

tmpSQL := tmpSQL + ' FROM ';

 

    

for i:=0 to tmpPropList.PropCount-1 do

    

begin

       

case tmpPropList.Props[i]^.PropType^.Kind of

         

tkClass:

           

begin

             

tmpObj := GetObjectProp(pTO, tmpPropList.Props[i]);

             

tmpProp2 := TDataTransferObject(tmpObj).FPropList;

             

tmpTbname := TDataTransferObject(tmpObj).tbName;

             

tmpSQL := tmpSQL + tmpTbname+',';

           

end;

       

end;

    

end;

 

    

tmpSQL := Copy(tmpSQL,0, length(tmpSQL)-1);

    

tmpSQL := tmpSQL + ' Where '+pTO.IndexInfo;

 

    

Result := tmpSQL;

 

  

end;

 

end;

 

  

//

明细表:


  

TDetail = class(TDataTransferObject)

  

public

    

person: TPersonBasVO;

    

card: TCardBasVO;

  

published

    

Property Fperson : TPersonBasVO  

index  

0 Read person  

Write person;

    

Property Fcard  

: TCardBasVO index  

1 Read card  

Write card;

  

public

    

constructor Create(tmpPer: TPersonBasVO; tmpCard: TCardBasVO);

  

end;

用法如下:


 

//-----------------------------------------------

  

//

明细表测试


  

//personVO.PK_Dno := '001';

 

  

Detail := TDetail.Create(personVO, CardVO);

  

rdmDS.SelectRDMDS(Detail, ClientDataSet2);

  

//-----------------------------------------------    

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值