我现在和朋友一起开发一个小项目,把每个表结构都定义为一个类,然后每条记录都为一个对象,然后读写都对该对象进行操作,这样的开发方法好吗?感觉有点烦索,但又好像用起来比较方便,到底我们这种方法是不是在走弯路呢?迷茫。高人指点下!
解决方案 »
- delphi XE内存泄露检查问题
- delphi如何修改系统默认的浏览器???
- 一个批量修改数据,怎么写成存储过程?
- C++代码转换为Delphi时字符串前的 L 如何处理?
- 大家看看这个sql语句错在哪里?
- 定时拨号的简单问题。。
- 有谁知道DBRadioGroup和adotable配合使用时,为什么不会选中字段中的值?
- 已经将一个应用程序放到右下角的任务栏中,如何动态的改变它的图标呢
- 如何在安装程序中放入多个目录
- 我写的一封信,大家来看看。给我点启发。
- [MDI]父窗体有1treeview,1DBgrid,如何让子窗体生成时能遮盖DBGrid,不遮盖TreeView
- delphi应用程序连接数据库问题
表,数据集,都已经在delphi中可直接操作的。
这两种方式各有优点,并且一直在争论到底哪一种更好
delphi中对dataset的支持非常好,用delphi的人也对该模式运用十分熟练,如果你在delphi版问这个问题,绝大部分人都不会支持你的做法的,如果你去java或者.net,支持你的人可能会多些
如果你是基于VCL架构来开发的话,我还是建议你使用dataset,如果你是基于delphi.net,那么我建议你使用ECO,其实你要做的,ECO已经做得很好了,没必要重复前人的工作
我个人觉得,面向对象的数据库开发方式是以后的趋势,dataset的方式只适合(中)小型应用
SysUtils, Classes, DB, ADODB;const MAX_LINE = '20';
type
TMyField = Class(TObject)
private
FIsChange: Boolean;
FFieldName: string;
FFieldValue: string;
FDataType: TFieldType;
procedure SetFieldValue(const Value: string);
public
property IsChange : Boolean read FIsChange; //是否改变,只读
property FieldValue:string read FFieldValue write SetFieldValue; //字段值
property FieldName:string read FFieldName; //字段名 ,只读
property DataType:TFieldType read FDataType; //字段的数据类型,只读
constructor Create(aFieldName:string;aFieldType:TFieldType;aValue:string='');
destructor Destroy;override;
end;
type
TCommonInfo = class(TObject) //该类可以作为其它类的基类进行扩展
private
FFieldCount: integer;
UpdateFields:string; //要修改的字值和值串 ,保存到数据库时用
FFields:array of TMyField;
FQry:TAdoQuery;
FTableName: String;
FKeyFields: string;
function GetFieldType(aFieldName:String):TFieldType; overload;
function GetFieldType(Index:integer):TFieldType; overload;
function IsValidOp(aop:String):Boolean; //是否为有效的操作符
function GetMainCondition:string; //根据主键获得条件,获取 where 后面的条件子句
function UniteField(aField:TMyField;aand:boolean=true;aValue:String=''):String; //连接字段值和条件,中间的参数代表是否加and运算符
function UniteStr(aFieldName:string;aFieldValue:string;aand:boolean=true):String;//联接含有字段串的字段,加引号 ,最后一个参数代表是否加 and
function UniteInt(aFieldName:string;aFieldValue:string;aand:boolean=true):String;//接接不加引号的字段 ,最后一个参数代表是否加 and
function IsValidFieldIndex(index:integer):boolean; //检查索引是否有效
procedure InitField; //初始化字段数组
function IsValidFieldName(aFieldName:string) : Boolean; //是否为有效的字段名
function IsKeyField(aFieldName:string):boolean; //字段名是否为主键
function SelectSQL(aSQL:string):Boolean; //执行返回结果的SQL,并给相应的域赋值
protected
property TableName:String read FTableName; //只读,表名
function GetInfoWithCondition(aFieldName,aOp,aValue: string):Boolean;overload; //根据条件获取信息 三个参数分别为:操作数,操作符,值
function GetInfoWithCondition(aCondition:String):boolean;overload; //根据条件取数据
function IsChanged:Boolean; //判断所有的字段值是否改变
function GetFieldValue(aFieldName:string) : String; overload; //根据字段名获取字段值
function getFieldValue(Index:integer):string; overload; //根据索引获取字段值
function SetFieldValue(aFieldName:String;aValue:String):boolean; overload; //根据字段名设置字段名
function SetFieldValue(Index:integer;aValue:String):Boolean;overload; //根据索引设置字段值
function GetFieldName(Index:integer):String; //根据索引获取字段名
public
function PerformSQL(aSql:string):boolean; //值行不返回结果的SQL
property FieldCount:integer read FFieldCount; //字段总数
property KeyFields:string read FKeyFields; //主键字段
function SaveToDataBase():Boolean; //保存当前数据到数据库
constructor Create(aTableName:String;Constr:String;aKeyFields:String); //参数分别为:表名,连接字符串,主键的的集合,如:ID;ANAME;
Destructor Destroy; override;
end;implementation{ TMyField }constructor TMyField.Create(aFieldName: string;aFieldType: TFieldType;aValue:String='');
begin
self.FFieldName := aFieldName;
//showmessage(self.FFieldName);
self.FisChange := false;
self.FDataType := aFieldType;
self.FFieldValue := aValue;
inherited create;
end;destructor TMyField.Destroy;
begin
inherited;
end;procedure TMyField.SetFieldValue(const Value: string);
begin
if FFieldValue <> Value then
begin
FFieldValue := Value;
FIsChange := true;
// showMessage('change'+Value);
end;
end;{ TCommonInfo }constructor TCommonInfo.Create(aTableName, Constr: String; aKeyFields:String);
begin
FTableName := aTableName;
FQry := TADOQuery.Create(nil);
FQry.ConnectionString := Constr;
FKeyFields := aKeyFields;
InitField;
inherited create;
end;destructor TCommonInfo.Destroy;
var
i:integer;
begin
FQry.Free;
for i := 0 to high(FFIelds) do
begin
if assigned(FFIelds[i]) then
FFields[i].Free;
end;
inherited;
end;function TCommonInfo.GetFieldValue(aFieldName: string): String;
var
i:integer;
begin
result := '';
if not IsValidFIeldName(aFieldName) then exit;
for i := 0 to FFieldCount-1 do
if UpperCase(FFields[i].FieldName) = UpperCase(aFieldName) then
begin
result := FFields[i].FieldValue;
break;
end;
end;function TCommonInfo.GetFieldValue(Index: integer): string;
begin
result := '';
if (Index < 0) or (Index >= FieldCount) then
raise Exception.Create('Field Index out of bounds!');
result := FFields[Index].FieldValue;
end;function TCommonInfo.GetFieldName(Index: integer): String;
begin
result := '';
if not IsValidFieldIndex(Index) then exit;
result := FFIelds[Index].FieldName;
end;procedure TCommonInfo.InitField;
var
i:integer;
begin
with FQry do
begin
close;
sql.Text := Format('select Top %s * from %s where 1<>2',[MAX_LINE,FTableName]);
open;
end;
FFieldCount:= FQry.FieldCount;
SetLength(FFields,FFieldCount);
for i:=0 to FFieldCount-1 do
begin
FFields[i] := TMyField.Create(Fqry.Fields[i].FieldName,Fqry.Fields[i].DataType);
end;
end;function TCommonInfo.IsChanged: Boolean;
var
i:integer;
begin
result := false;
UpdateFields := '';
for i:=0 to FFieldCount-1 do
begin
if self.FFields[i].IsChange = true then
begin
Result := true;
if Length(UpdateFields) <= 0 then
UpdateFields := UpdateFields + UniteField(FFields[i],false) //将改变的字段和值连起来,保存到数据库的时候用
else UpdateFields := UpdateFields + ' , ' + UniteField(FFields[i],false); //false 代表不加 and连接符
end
end;
end;
var
i:integer;
begin
result := false;
if not IsValidFIeldName(aFieldName) then begin {showmessage('set value exit');}exit;end;
for i := 0 to FFIeldCount-1 do
begin
if UpperCase(FFields[i].FieldName) = UpperCase(aFieldName) then
begin
FFIelds[i].FieldValue := aValue;
break;
end;
end;
result := true;
end;function TCommonInfo.SaveToDataBase: Boolean;
var
i:integer;
s:string;
begin
result := false;
if IsChanged then
s := 'Update ' + FTableName + ' set ' + UpdateFields + 'Where 1=1 ' + GetMainCondition
else begin {showmessage('not change!');}exit;end;
// showmessage(s);
result := self.PerformSQL(s);
end;function TCommonInfo.SetFieldValue(Index: integer; aValue: String): Boolean;
begin
result := false;
if not IsValidFieldIndex(Index) then exit;
FFIelds[Index].FieldValue := aValue;
result := true;
end;
function TCommonInfo.IsValidFieldIndex(index:integer): boolean;
begin
result := false;
if (Index < 0) or (Index >= FieldCount) then
begin
raise Exception.Create('Field Index out of bounds!');
exit;
end;
result := true;
end;function TCommonInfo.IsKeyField(aFieldName:string): boolean;
begin
result := pos(UpperCase(aFieldName),UpperCase(FKeyFields)) > 0;
//showmessage(aFieldName+':'+FKeyFIelds+':'+booltostr(result,true));
end;function TCommonInfo.IsValidFieldName(aFieldName: string): Boolean;
var
i:integer;
begin
result := true;
for i := 0 to FFIeldCount-1 do
begin
if UpperCase(FFIelds[i].FieldName) = UpperCase(aFieldName) then
begin
exit;
end;
end;
result := false;
end;function TCommonInfo.UniteInt(aFieldName, aFieldValue: string;aand:boolean=true): String;
begin
if aand then
result := Format(' and %s = %s ',[aFieldName,aFieldValue])
else result := Format(' %s = %s ',[aFieldName,aFieldValue]);
//showmessage('UniteInt result:'+result);
end;function TCommonInfo.UniteStr(aFieldName, aFieldValue: string;aand:boolean=true): String;
begin
if aand then
result := Format(' and %s = ''%s'' ',[aFieldName,aFieldValue])
else result := Format(' %s = ''%s'' ',[aFieldName,aFieldValue]);
end;function TCommonInfo.GetMainCondition: string;
var
i:integer;
begin
result := '';
//showmessage('getmaincondition'); 这句执行到了,IsKeyField这句有总题
for i := 0 to FFieldCount -1 do
begin
if IsKeyField(FFields[i].FieldName) then
begin
// showmessage(FFIelds[i].FieldName);
result := result + UniteField(FFIelds[i]);
end;
end;
end;function TCommonInfo.UniteField(aField: TMyField;aand:boolean=true;aValue:string=''): String;
begin
result := '';
if aField.DataType = ftstring then
begin
if aValue <>'' then
result := UniteStr(aField.FieldName,aValue,aand)
else
result := UniteStr(aField.FieldName,aField.FieldValue,aand)
end
else
begin
if aValue <>'' then
result := UniteInt(aField.FieldName,aValue,aand)
else
result := UniteInt(aField.FieldName,aField.FieldValue,aand);
end;
end;function TCommonInfo.PerformSQL(aSql: string): boolean;
var
i:integer;
begin
result := false;
try
with FQry do
begin
close;
sql.Text := aSql;
ExecSQL;
end;
except
result := false;
exit;
end;
result := true;
end;function TCommonInfo.GetInfoWithCondition(aFieldName:string;aOp:string;aValue: string): Boolean;
var
i:integer;
s:string;
begin
result := false;
if not IsValidOp(aop) then begin exit;end;
if not IsValidFieldName(aFieldName) then begin exit;end;
if GetFieldType(aFieldName) = ftString then
s :=Format('select top %s * From %s where %s %s ''%s''',[MAX_LINE,FTableName,aFieldName,aop,aValue])
else s :=Format('select top %s * From %s where %s %s %s',[MAX_LINE,FTableName,aFieldName,aop,aValue]);
result := self.SelectSQL(s)
end;
function TCommonInfo.IsValidOp(aop: String): Boolean;
begin
result := (aop = '<') or (aop = '>') or (aop = '>=') or (aop = '<=') or (aop = '<>') or (aop = '=');
end;function TCommonInfo.GetFieldType(aFieldName: String): TFieldType;
var
i:integer;
begin
if not IsValidFieldName(aFieldName) then exit;
for i :=0 to FFIeldCount -1 do
begin
if UpperCase(FFIelds[i].FieldName) = UpperCase(aFieldName) then
begin
result := FFields[i].DataType;
break
end;
end
end;function TCommonInfo.GetFieldType(Index: integer):TFieldType;
begin
if not IsValidFieldIndex(Index) then exit;
result := FFields[Index].DataType;
end;function TCommonInfo.GetInfoWithCondition(aCondition: String): boolean;
var
s:String;
begin
result := false;
s :=Format('select top %s * From %s where %s',[MAX_LINE,FTableName,aCondition]);
if SelectSQL(s) then
result := true;
end;function TCommonInfo.SelectSQL(aSQL: string): Boolean;
var
i:integer;
begin
result := true;
try
with FQry do
begin
close;
sql.Text := aSQL;
open
end;
for i := 0 to FFIeldCount -1 do
begin
FreeAndNil(FFields[i]);
if FQry.IsEmpty then
FFIelds[i] := TMyField.Create(FQry.Fields[i].FieldName,FQry.Fields[i].DataType,'')
else
FFields[i] := TMyField.Create(FQry.Fields[i].FieldName,FQry.Fields[i].DataType,Fqry.Fields[i].AsString);
// showmessage(FFIelds[i].FieldValue);
end
except
result := false;
end;
end;end.
unit Unit5;interfaceuses
SysUtils, Classes,unit4;Type
TStuInfo = class(TCommonInfo)
private
procedure SetAddr(const Value: string);
procedure SetAge(const Value: string);
procedure SetID(const Value: String);
procedure SetRes(const Value: String);
procedure SetSex(const Value: string);
procedure SetSname(const Value: String);
procedure SetTel(const Value: String);
function GetID: String;
function GetAddr: string;
function GetAge: string;
function GetRes: String;
function GetSex: string;
function GetSname: String;
function GetTel: String;
public
property ID:String read GetID write SetID;
property Sname:String read GetSname write SetSname;
property Sex:string read GetSex write SetSex;
property Age:string read GetAge write SetAge;
property Tel:String read GetTel write SetTel;
property Addr:string read GetAddr write SetAddr;
property Res:String read GetRes write SetRes;
Constructor Create(TableName,ConnStr,KeyFields:string);
Destructor Destroy; override;
function GetInfoWithId(aid:String):boolean;
function GetInfoWithSname(aSname:String):Boolean;
function GetInfoWithSex(aSex:String):Boolean;
function GetInfoWithTel(aTel:String):Boolean;
function GetInfoWithAge(aAge:String):Boolean;
function GetInfoWithAddr(aAddr:String):Boolean;
function GetInfoWithRes(aRes:String):boolean;
end;implementation{ TStuInfo }constructor TStuInfo.Create(TableName, ConnStr, KeyFields: string);
begin
inherited;
end;destructor TStuInfo.Destroy;
begin
inherited;
end;function TStuInfo.GetAddr: string;
begin
result := GetFieldValue('addr');
end;function TStuInfo.GetAge: string;
begin
result := GetFieldValue('age');
end;function TStuInfo.GetID: String;
begin
result := GetFieldValue('id');
end;function TStuInfo.GetInfoWithAddr(aAddr: String): Boolean;
begin
result := GetInfoWithCondition('Addr','=',aAddr);
end;function TStuInfo.GetInfoWithAge(aAge: String): Boolean;
begin
result := GetInfoWithCondition('Age','=',aAge);
end;function TStuInfo.GetInfoWithId(aid: String): boolean;
begin
result := GetInfoWithCondition('Id','=',aId);
end;function TStuInfo.GetInfoWithRes(aRes: String): boolean;
begin
result := GetInfoWithCondition('Res','=',aRes);
end;function TStuInfo.GetInfoWithSex(aSex: String): Boolean;
begin
result := GetInfoWithCondition('Sex','=',aSex);
end;function TStuInfo.GetInfoWithSname(aSname: String): Boolean;
begin
result := GetInfoWithCondition('Sname','=',aSname);
end;function TStuInfo.GetInfoWithTel(aTel: String): Boolean;
begin
result := GetInfoWithCondition('Tel','=',aTel);
end;function TStuInfo.GetRes: String;
begin
result := GetFieldValue('res');
end;function TStuInfo.GetSex: string;
begin
result := GetFieldValue('sex');
end;function TStuInfo.GetSname: String;
begin
result := GetFieldValue('Sname');
end;function TStuInfo.GetTel: String;
begin
result := GetFieldValue('tel');
end;procedure TStuInfo.SetAddr(const Value: string);
begin
SetFieldValue('addr',Value);
end;procedure TStuInfo.SetAge(const Value: string);
begin
SetFieldValue('Age',Value);
end;procedure TStuInfo.SetID(const Value: String);
begin
SetFieldValue('id',Value);
end;procedure TStuInfo.SetRes(const Value: String);
begin
SetFieldValue('Res',Value);
end;procedure TStuInfo.SetSex(const Value: string);
begin
SetFieldValue('sex',Value);
end;procedure TStuInfo.SetSname(const Value: String);
begin
SetFieldValue('sname',Value);
end;procedure TStuInfo.SetTel(const Value: String);
begin
SetFieldValue('Tel',Value);
end;end.
with FQry do
begin
close;
sql.Text := Format('select Top %s * from %s where 1<>2',[MAX_LINE,FTableName]);
open;
end;
FFieldCount:= FQry.FieldCount;
SetLength(FFields,FFieldCount);
for i:=0 to FFieldCount-1 do
begin
FFields[i] := TMyField.Create(Fqry.Fields[i].FieldName,Fqry.Fields[i].DataType);
end;如果数据库的结构改了这个通用的基类的结构也会跟着改的,然后在派生类中添加一个属性和读写方法就可以了!当然这个类并没有考虑到Blob字段!
频繁地使用Blob字段的系统性能会好吗?Blob字段这样的数据应该放在数据库里?
http://blog.csdn.net/badboy19800808/archive/2006/04/28/695610.aspx
多层的结构,客户端没有如adoquery,clientdataset之类的东西,只有业务类,对象,及显示控件(没有数据感知控件)。
客户端有个业务的基类,它最主要是利用RTTI方法,读取后代类的实例,将它的数据信息传到中间层和接收中间层的数据把它转化客户端业务类的信息。
中间层也有个基类,也是利用RTTI将后代的实例数据转化成一组sql命令,由它进行对数据库的操作,同样从数据库得到数据转成对象的信息,传给客户端。
在客户端写好了n多的方法,比如将对象的所有信息显示到界面等等
经过了这样的封装,并不是像有些人讲的为了后期维护方便,最重要的是提高代码复用,加速以后项目开发速度。公司做了n个项目了(基本都是大几十万的单),都是同一个架构(当然基类也在不断维护扩充)。还有很多好处,比如客户端的灵活性等等,不一一多说。当然也有缺点,效率肯定不如直接用dataset高等
要提醒楼主的是,这样的基类编写不是一两天搞定的,需要积累,实践,沉淀。(公司的底层基类是经过几年才逐渐成熟的)
如果只是为了一个,两个项目而去弄这个,那没必要。
在老板忙活不过来的时候可以考虑加中间管理层。这样的话,相对高效的做法也应该是完全n叉树。
1-n-n*n
如果在关系数据库已经可以处理的情况下;再添加中间管理结构,肯定要以牺牲运行效率为代价。