delphi 三层开发经验汇总
2010-02-22 22:59
344 查看
delphi很早就已经可以进行三层的开发了. 但一直到现在, 网上这方面的东西太少 了. 要么太老, 甚至不完全正确. 例如:
如
何进行多表更新(提交), 很多回复还是说用ADOConnection的事务, (如果要同时更新SQL SERVER和Oracle数据库的表怎么
办).
当然也有说用SetComplete, SetAbort的. 但说的很简单, 其中的注意事项又是什么呢. 还有的推荐看李维的那本分布
式开发的书. 那本书中是写了很多值得学习和了解的东西. 但有些东西已经过时了或者说的不详细, 例如win2000中已经有COM+了. COM+已
经整合了mts及其它一些东西了. 另个, 也有些贴子上有人说, 应用服务器上只用一个TDataSetPrivoder和一个
TDataSet(ADO, Query, DBXQuery之一)就可以了. 但具体怎么用呢?又看不到下文.
另外, 还有一些朋友
在用第三方的一些控件. 我看了一下, 大多就像个嵌入到IE中的ActiveX, 感觉也没有什么意思---直接弄个ActiveX到IE中就不行了.
1. 如何只用一个TDataSetPrivoder和一个TADOQuery.
delphi的TRemoteDataModule集成了IAppServer接口.并且实现了IAppServer接口的方法:
在应用服务器上, 只需要用这几个方法就可以了.
示例:unit Unit2;
说白点, 就是根据client端传来的表名. 动态的改变应用服务上的ADOQuery中的语句即可. 上面的例子中, 应用服务上只加入了两上方法
GETDATA, POSTDATA两个方法, 也可以为每个表都加入对应的GET和POST方法, 那么就不需要TABLENAME参数了.对于各户端
来说, 只知道应用服务中IAPPSERVER接口加入的方法就行了.
发现一个问题.用ADO连接到SQLSERVER时时候, 如果有类似下面的代码:
ADOQuery1.SQL.Text := 'update table set f1=:f1, f2=f2, f3:=f3';
ADOQuery1.Parameters[0].Value := 'a';
ADOQuery1.Parameters[0].Value := 'b';
ADOQuery1.Parameters[0].Value := 'c';
设
置每一个参数值的时候.会有
update table set f1=' ' where 1=2
update talbe set f2=' ' where 1=2
update talbe set f3=' ' where 1=2
在
SQLSERVER被编译. (我通过事件探查器发现的, 即使没有执行ADOQuery1.ExecSQL)
所以建议在应用服务器上直接拼成
(update table set f1=a, f2=b, f3=c)来执行会更好一些.
如果有image字段.改成text类型更
好一些.(好拼SQL语句).
客户端尽量多做一些工作,减轻应用服务器的负担也是应该考虑的.客户端给应用服务器的数据,尽量是
DELTA. 即有字段信息,也有数据信息,客户端也可以少写些代码.
当前手上的程序.应用服务器上有两上COM+对象, 一个是用来查
询, 一个是用来更新.效率还是很好的.
在COM+/MTS中的一点注意事项。
SetAbort并不同于RollbackTrans
SetComplete不
同于CommitTrans
SetAbort并不会导致事务立即回滚。只有在根对象失活(不一定是销毁)的时候,如果有一个对象调用了
SetAbort,才会回滚事务。
假如A对象创建了B对象,B创建了C对象。 也就是只有在A对象失活的时候。会检查是不是有对象进行了
SetAbort.如果有,就会取消执行的操作。
另外。在Create中进行某些初始操作要注意COM+被放到池中的情况,最好在
OnActivate, OnDeactivate中进行。
有时候COM+对象的Create文件根本不会被调用。
如果
你的COM+对象一定要在事务所中执行。调用IsInTransaction,如何不返回true, 就终止。
COM+对象在建立的时候,可以指定一个事务环境。
所以 应用服务器上有两上COM+对象, 一个是用来查询, 一个是用来更新.
可以更
好的考虑考虑了。
多表更新.只要将DataSetProvider.ResolveToDataSet:=True;就可以了.说明是使用ADO的驱动完成多表更新.
待续............
如
何进行多表更新(提交), 很多回复还是说用ADOConnection的事务, (如果要同时更新SQL SERVER和Oracle数据库的表怎么
办).
当然也有说用SetComplete, SetAbort的. 但说的很简单, 其中的注意事项又是什么呢. 还有的推荐看李维的那本分布
式开发的书. 那本书中是写了很多值得学习和了解的东西. 但有些东西已经过时了或者说的不详细, 例如win2000中已经有COM+了. COM+已
经整合了mts及其它一些东西了. 另个, 也有些贴子上有人说, 应用服务器上只用一个TDataSetPrivoder和一个
TDataSet(ADO, Query, DBXQuery之一)就可以了. 但具体怎么用呢?又看不到下文.
另外, 还有一些朋友
在用第三方的一些控件. 我看了一下, 大多就像个嵌入到IE中的ActiveX, 感觉也没有什么意思---直接弄个ActiveX到IE中就不行了.
1. 如何只用一个TDataSetPrivoder和一个TADOQuery.
delphi的TRemoteDataModule集成了IAppServer接口.并且实现了IAppServer接口的方法:
{ IAppServer } function AS_GetProviderNames: OleVariant; safecall; function AS_ApplyUpdates(const ProviderName: WideString; Delta: OleVariant; MaxErrors: Integer; out ErrorCount: Integer; var OwnerData: OleVariant): OleVariant; safecall; function AS_GetRecords(const ProviderName: WideString; Count: Integer; out RecsOut: Integer; Options: Integer; const CommandText: WideString; var Params, OwnerData: OleVariant): OleVariant; safecall; function AS_DataRequest(const ProviderName: WideString; Data: OleVariant): OleVariant; safecall; function AS_GetParams(const ProviderName: WideString; var OwnerData: OleVariant): OleVariant; safecall; function AS_RowRequest(const ProviderName: WideString; Row: OleVariant; RequestType: Integer; var OwnerData: OleVariant): OleVariant; safecall; procedure AS_Execute(const ProviderName: WideString; const CommandText: WideString; var Params, OwnerData: OleVariant); safecall;
在应用服务器上, 只需要用这几个方法就可以了.
示例:unit Unit2;
{$WARN SYMBOL_PLATFORM OFF} interface uses Windows, Messages, SysUtils, Classes, ComServ, ComObj, VCLCom, DataBkr, DBClient, Project1_TLB, StdVcl, ADODB, DB, Provider, ActiveX; type TMyRDM = class(TRemoteDataModule, IMyRDM) ClientDataSet1: TClientDataSet; DataSetProvider1: TDataSetProvider; ADOConnection1: TADOConnection; ADOQuery1: TADOQuery; procedure RemoteDataModuleCreate(Sender: TObject); private I: Integer; Params: OleVariant; OwnerData: OleVariant; // 手工加入 function InnerGetData(strSQL: String): OleVariant; function InnerPostData(Delta: OleVariant): Integer; protected class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); override; // 类型库加入的方法 function GetData(const TableName, Where: WideString): OleVariant; safecall; function PostData(const TableName: WideString; Delta: OleVariant): SYSINT; safecall; public { Public declarations } end; implementation {$R *.DFM} class procedure TMyRDM.UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); begin if Register then begin inherited UpdateRegistry(Register, ClassID, ProgID); EnableSocketTransport(ClassID); EnableWebTransport(ClassID); end else begin DisableSocketTransport(ClassID); DisableWebTransport(ClassID); inherited UpdateRegistry(Register, ClassID, ProgID); end; end; function TMyRDM.GetData(const TableName, Where: WideString): OleVariant; const SQL = 'select * from %s where %s'; begin Result := Self.InnerGetData(Format(SQL, [TableName, Where])); end; function TMyRDM.PostData(const TableName: WideString; Delta: OleVariant): SYSINT; var KeyField: TField; begin ClientDataSet1.Data := Delta; if ClientDataSet1.IsEmpty then Exit; { 这里假设每个表都有一个AutoID字段, 并且值是唯一的. 也可以根据表中, 改成相应的主键字段名. } KeyField := ClientDataSet1.FindField('AutoID'); if KeyField=nil then raise Exception.Create(' 键值字段未发现.'); if KeyField.IsNull then begin ADOQuery1.SQL.Text := 'select * from '+TableName+' where 1>2'; end else begin ADOQuery1.SQL.Text := 'select * from '+TableName+' where AutoID='+QuotedStr(KeyField.AsString); ADOQuery1.Open; with ADOQuery1.FieldByName('AutoID') do ProviderFlags := ProviderFlags + [pfInKey]; DataSetProvider1.UpdateMode := upWhereKeyOnly; end; ADOQuery1.Open; Result := InnerPostData(Delta); end; function TMyRDM.InnerGetData(strSQL: String): OleVariant; begin // 必须是CLOSE状态, 否则报错. if ADOQuery1.Active then ADOQuery1.Active := False; Result := Self.AS_GetRecords('DataSetProvider1', -1, I, ResetOption+MetaDataOption, strSQL, Params, OwnerData); end; function TMyRDM.InnerPostData(Delta: OleVariant): Integer; begin Self.AS_ApplyUpdates('DataSetProvider1', Delta, 0, Result, OwnerData); end; procedure TMyRDM.RemoteDataModuleCreate(Sender: TObject); begin Self.ADOQuery1.Connection := Self.ADOConnection1; Self.DataSetProvider1.DataSet := Self.ADOQuery1; Self.DataSetProvider1.Options := Self.DataSetProvider1.Options + [poAllowCommandText]; Self.ADOConnection1.Open; end; initialization TComponentFactory.Create(ComServer, TMyRDM, Class_MyRDM, ciMultiInstance, tmApartment); end.
说白点, 就是根据client端传来的表名. 动态的改变应用服务上的ADOQuery中的语句即可. 上面的例子中, 应用服务上只加入了两上方法
GETDATA, POSTDATA两个方法, 也可以为每个表都加入对应的GET和POST方法, 那么就不需要TABLENAME参数了.对于各户端
来说, 只知道应用服务中IAPPSERVER接口加入的方法就行了.
发现一个问题.用ADO连接到SQLSERVER时时候, 如果有类似下面的代码:
ADOQuery1.SQL.Text := 'update table set f1=:f1, f2=f2, f3:=f3';
ADOQuery1.Parameters[0].Value := 'a';
ADOQuery1.Parameters[0].Value := 'b';
ADOQuery1.Parameters[0].Value := 'c';
设
置每一个参数值的时候.会有
update table set f1=' ' where 1=2
update talbe set f2=' ' where 1=2
update talbe set f3=' ' where 1=2
在
SQLSERVER被编译. (我通过事件探查器发现的, 即使没有执行ADOQuery1.ExecSQL)
所以建议在应用服务器上直接拼成
(update table set f1=a, f2=b, f3=c)来执行会更好一些.
如果有image字段.改成text类型更
好一些.(好拼SQL语句).
客户端尽量多做一些工作,减轻应用服务器的负担也是应该考虑的.客户端给应用服务器的数据,尽量是
DELTA. 即有字段信息,也有数据信息,客户端也可以少写些代码.
当前手上的程序.应用服务器上有两上COM+对象, 一个是用来查
询, 一个是用来更新.效率还是很好的.
在COM+/MTS中的一点注意事项。
SetAbort并不同于RollbackTrans
SetComplete不
同于CommitTrans
SetAbort并不会导致事务立即回滚。只有在根对象失活(不一定是销毁)的时候,如果有一个对象调用了
SetAbort,才会回滚事务。
假如A对象创建了B对象,B创建了C对象。 也就是只有在A对象失活的时候。会检查是不是有对象进行了
SetAbort.如果有,就会取消执行的操作。
另外。在Create中进行某些初始操作要注意COM+被放到池中的情况,最好在
OnActivate, OnDeactivate中进行。
有时候COM+对象的Create文件根本不会被调用。
如果
你的COM+对象一定要在事务所中执行。调用IsInTransaction,如何不返回true, 就终止。
COM+对象在建立的时候,可以指定一个事务环境。
所以 应用服务器上有两上COM+对象, 一个是用来查询, 一个是用来更新.
可以更
好的考虑考虑了。
多表更新.只要将DataSetProvider.ResolveToDataSet:=True;就可以了.说明是使用ADO的驱动完成多表更新.
待续............
相关文章推荐
- delphi 三层开发经验汇总[转]
- delphi 三层开发经验汇总
- delphi 三层开发经验汇总
- Delphi的三层开发初学经验
- Delphi的三层开发初学经验
- delphi项目开发经验2008年09月18日 星期四 10:07随着项目的失败,这些天一直在总结失败的原因,到底是为什么?
- Delphi三层程序开发
- Delphi开发经验技巧:随机产生中奖号码
- Python开发经验汇总
- android studio 2.2 NDK开发经验总结及相关错误汇总(旧版NDK开发转新版NDK开发经验)
- iOS 音频开发经验汇总
- Delphi三层数据库开发应用
- wince开发经验汇总
- Delphi三层开发小技巧:TClientDataSet的Delta妙用
- Delphi xe5 手机开发经验(新手级别)
- Delphi 三层框架开发客户端开发
- Delphi三层数据库开发应用