程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> CS結構中成批保存CLIENTDATASET中的數據

CS結構中成批保存CLIENTDATASET中的數據

編輯:Delphi
 

  這應該不算是什麼技巧,估計有數據庫方面程序的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;
    否則就不用那麼麻煩自已寫代碼來處理了;

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved