C\S结构中成批保存CLIENTDATASET中的数据

2008-04-09 04:21:29来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

这应该不算是什么技巧,估计有数据库方面程序的DELPHI程序员都知道;本来没有写想到
需要把它写成一篇贴子,但前不久看个别刚入门的兄弟的代码时。才发展他们还在刀
耕火种,为此才想把它写出来算是对入门的兄弟们的一点帮助,让大侠们见笑了;
我们都知道TCLIENTDATASET有把对它其中的数据所做的修改记录下来的功能;如果需要还可以将
修改回复到以前的某个状态,而且结合DATASETPROVIDER还可能自动完成改动到SQL映射,将改动成批提交到数据库中
这个特性对于写数据库程序来说非常有用。其实我所说的保存CLIENTDATASET的数据也是利用这个特性来实现的;

代码很简单:

unit uCDSSave;

interface

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

type
TSaveCDS = class (TObject)
private
Fileds: TStrings;
FProvider: TDataSetProvider;
procedure ReconcileError(DataSet: TCustomClientDataSet; E: EReconcileError;
UpdateKind: TUpdateKind; var Action: TReconcileAction);
public
constructor Create;
destructor Destroy; override;
procedure CDSSave(CDS:TClientDataSet;TableName,keyFiled,
NoSaveFileds:String;KeyUpdate:Boolean=False);
procedure DataSetProviderUpdateData(Sender: TObject;DataSet:
TCustomClientDataSet);
procedure SetCDS(KeyFiled,NoSavefields:string;KeyUpdate:Boolean=False);
property Provider: TDataSetProvider read FProvider write FProvider;
end;

implementation
{
*********************************** TSaveCDS ***********************************
}
constructor TSaveCDS.Create;
begin
inherited Create;
Fileds:=TStringList.Create;
FProvider:=TDataSetProvider.Create(nil);
FProvider.UpdateMode:= upWhereKeyOnly ;
FProvider.Options:=FProvider.Options [poAllowMultiRecordUpdates];
end;

destructor TSaveCDS.Destroy;
begin
FreeAndNil(FProvider);
FreeAndNil(Fileds);

inherited Destroy;

end;

procedure TSaveCDS.CDSSave(CDS:TClientDataSet;TableName,keyFiled,
NoSaveFileds:String;KeyUpdate:Boolean=False);
var
ErrCount: Integer;
begin
CDS.CheckBrowseMode;
if CDS.ChangeCount<1 then Exit;
CDS.OnReconcileError:= ReconcileError; //调用保存前客户代码应该先调用SetCDS指定保存的信息;
// SetCDS(CDS,keyFiled,NoSaveFileds,KeyUpdate);
// FProvider.ApplyUpdates(CDS.Delta,0,ErrCount)
try
CDS.Reconcile(FProvider.ApplyUpdates(CDS.Delta,0,ErrCount));
finally
CDS.OnReconcileError:=nil;
end;

end;

procedure TSaveCDS.DataSetProviderUpdateData(Sender: TObject;DataSet:
TCustomClientDataSet);
var
i: Integer;
v: OLEVariant;
KeyUpdate: Boolean;
begin
varClear(v);
V:=DataSet.GetOptionalParam(''''KEYUPDATE'''');
if not (VarIsNull(V) or VarIsClear(V)) then KeyUpdate:=true
else KeyUpdate:=False;

V:=DataSet.GetOptionalParam(''''KEYFILED'''');
if Assigned(DataSet.FindField(VarToStr(V))) then
if KeyUpdate then
DataSet.FindField(VarToStr(V)).ProviderFlags:=[pfInupdate,pfinKey]
else
DataSet.FindField(VarToStr(V)).ProviderFlags:=[pfinKey];
V:=DataSet.GetOptionalParam(''''NOSAVEFILEDS'''');
if (VarIsNull(V) or VarIsClear(V)) then Exit;
Fileds.Clear;
Fileds.Text:=VarToStr(V);
if Fileds.Count<1 then Exit; //将不保存的传过来 ,在这个事件中解析
//这只是一种方法而已,当然也有其他的方式,如用BYTE数组打包到数据包中;请读者自已考虑实现了;
for i:=1 to Fileds.Count-1 do
if Assigned(DataSet.FieldByName(Fileds[i])) then DataSet.FieldByName(Fileds[i]).ProviderFlags:=[];
end;

procedure TSaveCDS.ReconcileError(DataSet: TCustomClientDataSet; E:
EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction);
begin
Raise E; //只是简单的抛出例外,如有自己的处理请自己实现了;
end;

procedure TSaveCDS.SetCDS(KeyFiled,NoSavefields:string;KeyUpdate:Boolean=False);
begin
CDS.SetOptionalParam(''''TABLE_NAME'''' ,TableName,true);//指定要存入的表名;
CDS.SetOptionalParam(''''KEYFILED'''' ,keyFiled,true);//指定要主建名;
CDS.SetOptionalParam(''''NOSAVEFILEDS'''' ,NoSaveFileds,true);//指定不要存入的字段列表;
if KeyUpDate then
CDS.SetOptionalParam(''''KEYUPDATE'''' ,1,true);// 指定主健是否要更新字段列表

end;

end.

这段代码不一定是最优的实现,主要是想给出一个思路,用时可以根据实际情况改动,例如:本来程序是用的MIDAS来实现,则
就可以直接用CLIENTDATASET连接中间的TDATASETPROVIDER来实现;有一点要特别说明的是我发现在D5时,在前端的CLIENTDATASET
中直接设定各个字段的PROVIDERFLAG后不会被打包到Delta传给TDATASETPROVIDER;D7中好象也有此问题,不知是我看错了,还是D的BUG;
否则就不用那么麻烦自已写代码来处理了;

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:读书笔记:Delphi5 开发人员指南 第一章

下一篇:设计模式在制作升级文件包中的应用