C\S结构中成批保存CLIENTDATASET中的数据
这应该不算是什么技巧,估计有数据库方面程序的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;
否则就不用那么麻烦自已写代码来处理了;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库