[转载]TManagedDataSet和DataSetPool的实现
Delphi中使用最多的大概是AdoExpress组件,这是Borland封装了Microsoft的Ado的东东,使用频率最多的TAdoDataSet对应了Ado原生的RecordSet,在功能上做了一些增强,但用法基本一致,用多了就感觉TAdoDataSet还有扩充和改造的地方。
由于代码中使用了很多的TAdoDataSet控件,创建和释放对象非常频繁,而且每次创建后都要设置很多基本相同的属性,颇为麻烦。于是想到可以实现一个记录集池,每次当需要一个记录集时,从这个池中得到一个空闲且符合要求的(只读或可读写),用完了就被池回收,如果池中记录集不够,就自动生成新的记录集对象。
首先要做的是改造TAdoDataSet,我写了一个TManagedDataSet,继承自TAdoDataSet,可以自己知道自己是被人使用还是空闲(通过IsUsed()),重写了Free(),把本来释放的动作改为仅是把自己设置为空闲,并清除状态(Session)信息,并可以通过Source()返回一个指向自己的TDataSource对象。
有了这些基础后,就可以很快的构建TDataSetPool类了,这个类仅是保存可用的TManagedDataSet对象,通过GetDataSet(WantType : TManagedDataSetType)返回一个空闲的数据集对象,如果池中没有空闲的,就新建一个返回。TManagedDataSetType是枚举类,标识只读数据集和读写数据集(只读数据集可通过优化CursorType和LockType来加快读数据速度)。
下面的代码是直接从我做的一个项目的源文件中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.

浙公网安备 33010602011771号