在delphi开发数据库应用程序时,经常需要和数据集打交道,TDataSet 提供了浏览,修改数据等操作,使用非常方便。但也正因为使用方便,所以代码中到处充斥着 FieldByName 这样的语句,随着时间的推移,项目的维护修改,整个代码阅读起来很艰涩,且DataSet作为数据存储的中心,经常在多个目模块间传递引用,而其他模块也很方便修改DataSet中的数据,常常容易造成数据混乱,发生错误。
在实际工作中,发现解决上面问题的较好的方法是,将 DataSet 的数据转化为业务对象,并且业务对象的定义统一放置于一个单元中,这样在其它模块中使用的是业务对象,代码阅读起来容易理解,方便修改,且在一个单元中维护对象的定义也为日后维护提供了方便。
所以,如何将 DataSet 转为为业务对象就成为关键,在这里我提供一个简单例子,希望neng抛砖引玉的作用。
例子:
业务对象为 People
unit uMap_Peo;
interface
uses DB;
type
PeoRec = record //Peo结构
Name: string;
Age: Integer;
Nation: string;
end;
PPeoRec = ^PeoRec;
TPeoField = (Name, Age, Nation); //Peo数据字段定义
const
PeoFieldName: array[TPeoField] of string = ( //Peo数据库中字段名
'Name', 'Age', 'Nation'
);
type
TPeo = class
private
aDs : TDataSet;
public
constructor Create(aDs: TDataSet);
function GetProps(Prop: TPeoField): Variant;
procedure SetProps(Prop: TPeoField; const Value: Variant);
property Prop[Prop: TPeoField]:Variant read GetProps write SetProps; default; //默认属性
property Data:TDataSet read aDs;
end;
procedure NewPeo(aDs: TDataSet; var aPeo : PeoRec);
implementation
{ TPeo }
procedure NewPeo(aDs: TDataSet; var aPeo : PeoRec);
var
aDsPeo: TPeo;
begin
aDsPeo:= TPeo.Create(aDs);
try
aPeo.Name := aDsPeo[Name];
aPeo.Age := aDsPeo[Age];
aPeo.Nation := aDsPeo[Nation];
finally
aDsPeo.Free;
end;
end;
constructor TPeo.Create(aDs: TDataSet);
begin
inherited Create;
Self.aDs := aDs;
end;
function TPeo.GetProps(Prop: TPeoField): Variant;
begin
Result := aDs.FieldByName(PeoFieldName[Prop]).Value;
end;
procedure TPeo.SetProps(Prop: TPeoField; const Value: Variant);
begin
aDs.FieldByName(PeoFieldName[Prop]).Value := Value;
end;
end.
TPeo 作为 DataSet 的影射集,和 DataSet 一样,操作只影响当前记录,使用如:
var
Peo: TPeo
.......
edtname.text := Peo[Name];
edtAge.text := Inttostr(Peo[Age]);
edtNation.text := Peo[Nation];
....
一般来说,创建 TPeo 的模块是数据管理中心,集中管理这个TPeo 中的 DataSet 的数据。
其他模块要使用此数据集中的一条或多条数据,应使用 DataSet 的数据副本,而不是将DataSet 传递过去,从而避免对数据中心管理DataSet产生影响。
使用 DataSet 的数据副本, 也就是使用 PeoRec 记录结构,它占用资源小,操作方便,值传递.
var
aPeo: PeoRec;
.......
aPeo.Name := 'XXX';
........
通过对DataSet的对象化,传递数据副本,有效避免了以往程序中多模块间相互粘连多个数据集的情况,有效划分了模块间的责任,毕竟很多的处理需要的是对象而不是数据集本身.
在delphi2005之后,编译器支持一种新的数据类型 records 如:
type
PeoRec = record
var
Age: Integer;
Name: string;
class var
Nation: string;
procedure SayHello();
procedure SetAge(value: integer);
constructor Create(const aName: string; val: Integer); //可选的
property AgeProp: Integer read Age write SetAge;
class property NationProp: String read Nation ;
end;
可以看到,Records 可以将 Record类型 像对象那样看待,允许包含过程,方法,属性。使用起来更方便了。