• 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;
      否则就不用那么麻烦自已写代码来处理了;

  • 相关阅读:
    【BZOJ4979】凌晨三点的宿舍(分治)
    【BZOJ5469】【FJOI2018】—领导集团问题(线段树合并)
    【BZOJ5470】【FJOI2018】—所罗门王的宝藏(BFS)
    【BZOJ5252】【洛谷P4383】【2018九省联考】—林克卡特树(二分+树形dp)
    【BZOJ5251】【九省联考2018】—劈配(网络流)
    【BZOJ5250】【2018九省联考】—秘密袭击(树形dp)
    【BZOJ5249】【九省联考2018】—IIIDX(线段树)
    【BZOJ5248】【九省联考2018】—一双木棋(轮廓线dp)
    【BZOJ5337】【TJOI2018】—STR(后缀自动机+dp)
    node-mongo-服务器封装
  • 原文地址:https://www.cnblogs.com/94YY/p/2043513.html
Copyright © 2020-2023  润新知