TManagedDataSet和DataSetPool的实现

    技术2022-05-11  46

    TManagedDataSetDataSetPool的实现

     

             天天用Delphi,自己有了很多想法。写代码之余,有空闲时间就把一些东西整理成文档。

             Delphi中使用最多的大概是AdoExpress组件,这是Borland封装了MicrosoftAdo的东东,使用频率最多的TAdoDataSet对应了Ado原生的RecordSet,在功能上做了一些增强,但用法基本一致,用多了就感觉TAdoDataSet还有扩充和改造的地方。

             由于代码中使用了很多的TAdoDataSet控件,创建和释放对象非常频繁,而且每次创建后都要设置很多基本相同的属性,颇为麻烦。于是想到可以实现一个记录集池,每次当需要一个记录集时,从这个池中得到一个空闲且符合要求的(只读或可读写),用完了就被池回收,如果池中记录集不够,就自动生成新的记录集对象。

             首先要做的是改造TAdoDataSet,我写了一个TManagedDataSet,继承自TAdoDataSet,可以自己知道自己是被人使用还是空闲(通过IsUsed()),重写了Free(),把本来释放的动作改为仅是把自己设置为空闲,并清除状态(Session)信息,并可以通过Source()返回一个指向自己的TDataSource对象。

             有了这些基础后,就可以很快的构建TDataSetPool类了,这个类仅是保存可用的TManagedDataSet对象,通过GetDataSet(WantType : TManagedDataSetType)返回一个空闲的数据集对象,如果池中没有空闲的,就新建一个返回。TManagedDataSetType是枚举类,标识只读数据集和读写数据集(只读数据集可通过优化CursorTypeLockType来加快读数据速度)

             下面的代码是直接从我做的一个项目的源文件中Copy出来的,有些乱,仅做参考。

     

     

     

    unit ManagedDataSet;

     

    interface

     

    uses AdoDb, CommonDm, SysUtils, DB, dbgrids, ComObj, classes, contnrs;

     

    type

             TManagedDataSetType = (ReadOnly, Editable); // 猅羭摸

        TXlsExpAdapter = class

            private

               _sXlsCaption : string;

                _sXlsFileName : string;

                _bOverwriteExistFile : Boolean;

                                _asFieldName : TStringList;

                _asXlsTitle : TStringList;

                _aDataType : TObjectList;

                function GetDataType(const iniIndex : Integer) : TDataType;

                function GetFieldName(const iniIndex : Integer) : string;

                function GetXlsTitle(const iniIndex : Integer) : string;

            public

               constructor Create();

                destructor Destroy();

               property XlsCaption : string read _sXlsCaption Write _sXlsCaption;

                property XlsFileName : string read _sXlsFileName Write _sXlsFileName;

                property OverWriteExistFile : Boolean read _bOverwriteExistFile Write _bOverwriteExistFile;

                                procedure AddField(const insFieldName, insCaption : string; const intype : TDataType = ftUnKnown);

                procedure GetInfoFromDBGrid(const ingrid : TDBGrid);

                property DataType[const iniIndex : Integer] : TDataType read GetDataType;

                property FieldName[const iniIndex : Integer] : string read GetFieldName;

                property XlsTitle[const iniIndex : Integer] : string read GetXlsTitle;

                function Count() : Integer;

        end;

        TManagedDataSet = class(TAdoDataSet)

                       private

                _source : TDataSource;

                _type : TManagedDataSetType;

                _bUsed : Boolean;

     

                procedure SetDataSetType(const intype : TManagedDataSetType);

                function GetDataSource() : TDataSource;

            public

               constructor Create(const intype : TManagedDataSetType = Editable);

                destructor Destroy(); override;

                                procedure Use();

                procedure Free(); reintroduce; // 滦籠摸Freeぃ穦睦龟ㄒ

                property DataSetType : TManagedDataSetType read _type Write SetDataSetType;

                property IsUsed : Boolean read _bUsed;

                property Source : TDataSource read GetDataSource;

                function ExportToXls(const inadapter : TXlsExpAdapter) : Boolean;

        end;

     

    implementation

     

    function TXlsExpAdapter.Count() : Integer;

    begin

        Result := _asFieldName.Count;

    end;

     

    function TXlsExpAdapter.GetXlsTitle(const iniIndex : Integer) : string;

    begin

             if (iniIndex >= 0) and (iniIndex <= _aDataType.Count-1) then

        begin

        Result := _asXlsTitle[iniIndex];

        end;

    end;

     

    function TXlsExpAdapter.GetFieldName(const iniIndex : Integer) : string;

    begin

             if (iniIndex >= 0) and (iniIndex <= _aDataType.Count-1) then

        begin

        Result := _asFieldName[iniIndex];

        end;

    end;

     

    function TXlsExpAdapter.GetDataType(const iniIndex : Integer) : TDataType;

    begin

        if (iniIndex >= 0) and (iniIndex <= _aDataType.Count-1) then

        begin

            Result := TDataType(_aDataType[iniIndex]);

        end;

    end;

     

    procedure TXlsExpAdapter.GetInfoFromDBGrid(const ingrid : TDBGrid);

    var

             i, j : Integer;

        dt : TDataType;

    begin

             for i := 0 to ingrid.Columns.Count-1 do

        begin

                       if ingrid.Columns[i].Visible then

            begin

               dt := ftUnknown;

               for j := 0 to ingrid.FieldCount-1 do

                begin

                    if ingrid.Columns[i].FieldName = ingrid.Fields[j].FieldName then

                    begin

                        dt := ingrid.Fields[j].DataType;

                        Break;

                    end;

                end;

                Self.AddField(ingrid.Columns[i].FieldName, ingrid.Columns[i].Title.Caption, dt);

            end;

        end;  

    end;

     

    procedure TXlsExpAdapter.AddField(const insFieldName, insCaption : string; const intype : TDataType = ftUnKnown);

    var

             iIndex : Integer;

    begin

             iIndex := _asFieldName.IndexOf(insFieldName);

        if iIndex = -1 then

        begin

            _asFieldName.Add(insFieldName);

            _asXlsTitle.Add(insCaption);

            _aDataType.Add(TObject(intype));

        end

        else begin

            _asFieldName[iIndex] := insFieldName;

            _asXlsTitle[iIndex] := insCaption;

            _aDataType[iIndex] := TObject(intype);

        end;

    end;

     

    constructor TXlsExpAdapter.Create();

    begin

             _asFieldName := TStringList.Create();

        _asXlsTitle := TStringList.Create();

        _aDataType := TObjectList.Create();

    end;

     

    destructor TXlsExpAdapter.Destroy();

    begin

     

    end;

     

    function TManagedDataSet.ExportToXls(const inadapter : TXlsExpAdapter) : Boolean;

    var

             excelobj : OleVariant;

        i : Integer;

    begin

             Result := False;

       

             if not Self.Active then

            Exit;

     

             try

        excelobj := CreateOleObject('Excel.Application');

            excelobj.WorkBooks.Add;

        except

        Exit;

        end;

     

        if FileExists(inadapter.XlsFileName) and inadapter.OverWriteExistFile then

        begin

            DeleteFile(PChar(inadapter.XlsFileName));

        end

        else begin

            excelobj.Quit;

            Exit;

        end;

     

        for i := 0 to inadapter.Count-1 do

        begin

                      

        end;

    end;

     

    constructor TManagedDataSet.Create(const intype : TManagedDataSetType = Editable);

    begin

             inherited Create(nil);

             Self.Connection := DmCommon.Cnn;

        Self.CursorLocation := clUseClient;

        Self.Prepared := True;

        Self.CacheSize := 1000;

        if intype = ReadOnly then

        begin

        Self.CursorType := ctOpenForwardOnly;

        Self.LockType := ltReadOnly;

        end

        else if intype = Editable then

        begin

            Self.CursorType := ctStatic;

        Self.LockType := ltOptimistic;

        end;

     

        _type := intype;

        _bUsed := False;

    end;

     

    destructor TManagedDataSet.Destroy();

    begin

             if Self.Active then

        begin

                 Self.Close;

        end;

        if Assigned(_source) then

        begin

                 FreeAndNil(_source);

        end;

        inherited Destroy();

    end;

     

    procedure TManagedDataSet.Use();

    begin

        if _bUsed then

        begin

            raise Exception.Create('Cannot get a used managed dataset !');

        end;

     

        _bUsed := True;

    end;

     

    procedure TManagedDataSet.Free();

    begin

             if Self.Active then

        begin

        Self.Close;

        end;

     

        Self.CommandText := '';

        Self.Parameters.Clear; // 睲埃把计

        Self.MasterFields := ''; // 睲埃琿

        Self.DataSource := nil;

        Self.ExecuteOptions := []; // 睲埃磅︽匡兜

        _bUsed := False;

    end;

     

    procedure TManagedDataSet.SetDataSetType(const intype : TManagedDataSetType);

    begin

        if intype = _type then

        Exit;

     

        if intype = ReadOnly then

        begin

        Self.CursorType := ctOpenForwardOnly;

        Self.LockType := ltReadOnly;

        end

        else if intype = Editable then

        begin

            Self.CursorType := ctStatic;

        Self.LockType := ltOptimistic;

        end;

    end;

     

    function TManagedDataSet.GetDataSource() : TDataSource;

    begin

             if not Assigned(_source) then

        begin

                 _source := TDataSource.Create(nil);

        _source.AutoEdit := False;

                 _source.DataSet := Self;

        end;

        Result := _source;

    end;

     

    end.

     

     

     

     

     

    unit DataSetPool; // 癘魁栋GlobalVarい承セ摸Ы龟ㄒ跑秖

     

    interface

     

    uses ManagedDataSet, Contnrs, SysUtils, AdoDb, Db, CommonDm;

     

    type

             TDataSetPool = class

                       private

               _ads : TObjectList;

                function GetCount() : Integer;

            public

               constructor Create(const ini : Integer = 10);

                destructor Destroy(); override;

                property Count : Integer read GetCount;

                function GetDataSet(const intype : TManagedDataSetType = Editable) : TManagedDataSet;

                function GetAdoCommand() : TAdoCommand; // TAdoCommand睦パ秸ノ璽砫

        end;

     

    implementation

     

    constructor TDataSetPool.Create(const ini : Integer = 10);

    begin

             _ads := TObjectList.Create;

    end;

     

    destructor TDataSetPool.Destroy();

    begin

        FreeAndNil(_ads);

    end;

     

    function TDataSetPool.GetCount() : Integer;

    begin

             Result := _ads.Count;

    end;

     

    function TDataSetPool.GetDataSet(const intype : TManagedDataSetType = Editable) : TManagedDataSet;

    var

             i : Integer;

    begin

             Result := nil;

     

             for i := 0  to _ads.Count-1 do

        begin

                       if (not TManagedDataSet(_ads[i]).IsUsed) and (TManagedDataSet(_ads[i]).DataSetType = intype) then

            begin

                Result := TManagedDataSet(_ads[i]);

                Result.Use;

                break;

            end;

        end;

     

        if Result = nil then

        begin

                       _ads.Add(TManagedDataSet.Create(intype));

            Result := TManagedDataSet(_ads[_ads.Count-1]);

            Result.Use;

        end;

    end;

     

    function TDataSetPool.GetAdoCommand() : TAdoCommand;

    begin

             Result := TADOCommand.Create(nil);

        Result.Connection := DmCommon.Cnn;

    end;

     

    end.


    最新回复(0)