发信人: jetliu()
整理人: delphifan(2000-12-05 18:46:17), 站内信件
|
delphi学习心得(一)----数据记录的校验
---------------------------------------------------------------------- ----------
在数据库应用程序的开发中,对数据正确性和完整性的校验是必不可缺的一步。 这些检验工作通常包括:主码是否唯一;必填字段是否为空;数据类型是否正确; 数据是否超出范围等等.如果不对用户输入的数据进行校验便写入数据库表,就会 导致程序产生错误异常退出,使数据库里的数据变为脏数据,失去利用价值。
Delphi是开发数据库应用程序的利器。在用Delphi开发此类程序时,有多种校验 方法可供我们选择。其实我们可以选择在两个地方实施校验:一是程序中编写代 码;二是在数据库中如使用存储过程和触发器。第一种方法的优点是程序对数据 库的依赖小。比如,我可以选择SQL SERVER,也可以选择ACCESS、PARADOX等,即 使ACCESS不支持存储过程也没关系。第二种方法的优点是开销小,不需要把大量 的数据从库里掉出来让程序一条条的比较,校验的工作都是在后台完成的。当数 据库和程序不再同一台机器上时,能够减轻网络的负担。另一个优点是不用修改 程序就可以改变校验的逻辑,因为它是在源程序之外的。我倾向于用前一种方法 --在代码中校验。我觉得兼容性更重要一点。
一般的数据库应用程序主要由TDatabase、TTable、TQuery、TDatasoucre、TDBG rid、TEdit等组件组成。针对你的数据交互界面和使用的数据库的不同,校验的 方法也有所不同。方法大致有三种:
使用TTable事件
使用try语句
使用Application对象的OnException事件
使用TTable事件
TTable组件有很多有用的事件:beforePost、OnPostError、OnUpdateError、On DeleteError是较常用的。使用beforePost事件是主动出击的方法。当程序显式( 调用post方法)或隐式(修改后移动记录)激发Post事件之前产生beforePost事 件,典型的代码如下:
procedure TForm1.Table1BeforePost(DataSet: TDataSet);
Begin
if Dataset.FieldByName('ID').asString='' then//假设ID字段用户没有填入
begin
Beep; //发出声响,提示用户
MessageDlg('编号不能空着,请填入',mtError,[mbOK],0);//弹出对话框提示
Dbgrid1.SelectedIndex:=0;//移动焦点到错误的列,假设ID字段是第一列
Abort;//调用取消过程放弃更新动作,这是最关键的一步
end;
end;
当然也可以用Table中Field类的OnValidate事件,这样做的结果是用户每填完一 个字段都要检验。有时用户并不是按顺序填写字段,而你的检验警告却频繁跳出 打断用户的工作,这会让用户觉得很反感。和beforePost比起来,OnPostError对 于处理此类事情好像更专业一点。OnPostError是被动的,它假设用户输入的都是 正确的,只有产生了错误才来看看到底是哪儿出了问题。典型代码如下:
procedure TForm1.Table1PostError(DataSet: TDataSet; E: EDatabaseError; var Action:TDataAction);
begin
if Dataset.FieldByName('ID').asString='' then//假设ID字段用户没有填入
begin
Beep; //发出声响,提示用户
ShowMessage(E.Message)//弹出对话框提示错误信息
Action:=daAbort;//设置参数放弃更新动作
end;
我们看到,OnPostError事件提供有用的参数,E,Action。这对于错误处理很有帮 助,它也是我说OnPostError比beforePost更专业的原因。其他如OndeleteError 的使用方法大致相同。我只想在强调一下beforePost这类不是专门处理错误的事 件和OnPostError这种专用事件的区别。当TTable组件连接的表结构发生变化时他 们的区别就表现出来了。例如有个ID字段,原来是主码,现在不是了。那麽如果 用户输入了重复的ID时,beforePost还会一丝不苟的去指出主码不能重复(因为 你并没有修改代码),而OnPostError却能够体察到这一改变,不去提示用户更正 。因为重复的ID值也是合理的,OnPostError并没有被激发。这类在Table里校验 的方法,适合用于采用DBGrid形式作为数据交互界面的程序。这类界面的程序, 用户不会老老实实的按某个“确定”按钮来提交数据,有可能它会移动记录来产 生提交。所以我们只能站在一边等待错误产生后,再跳出来指责用户,所以校验 只有放在事件里完成。
使用try语句
据我的经验,也有OnPostError看不见错误的时候。比如使用SQL SERVER7.0,好像 所有的Error事件都失灵了一样,不管错误有多严重也不会激发它们,只有产生个 异常错误终止了程序。这时候,我只好用try..except异常处理机制来校验了。例 如,界面上有个确定按钮用来提交数据,可以这样写:
procedure TForm1.btnOkClick(Sender:TObject);
begin
try
Table1.Post;
except
On EDatabaseError do
if Dataset.FieldByName('ID').asString='' then//假设ID字段用户没有填入
begin
Beep; //发出声响,提示用户
MessageDlg('编号不能空着,请填入',mtError,[mbOK],0);//弹出对话框提示
end;//end try
end;
这种方法适用于用代码来改变数据的情况,就是Post,Delete,first,next等方法 都是你显式调用的,没有隐式激发的。换句话说,就是一切改变数据的机会都掌 握在你手中。通常使用Form排列几个DBEDIT等组件的交互界面适用此方法。
使用Application对象的OnException事件
当OnPostError事件失灵,你又不能限制用户提交数据的时候(碰到这种情况真是 够倒霉的),就只有使用Application对象的OnException属性了。你可以自己编 一个异常处理过程,把它挂到Application对象上。这样程序出的所有异常你都能 捕获到,当然包括提交数据错误引起的异常。在过程中你只处理和数据库有关的 部分。首先编一个异常处理过程:
procedure MyException(Sender: TObject; E: Exception);
begin
if (E is EDatabaseError) then//数据库类异常
if table1.FieldByName('ID').asString='' then//假设ID字段用户没有填入
begin
Beep; //发出声响,提示用户
ShowMessage(E.Message)//弹出对话框提示错误信息
end
else//不是数据库类错误
begin
ShowMessage(E.Message);//显示错误信息
Application.Terminate;//异常退出
end;
end;
再把这个处理过程挂到Application对象上。这步通常是在FormCreate事件里完成 的:
procedure TForm1.FormCreate(Sender:TObject)
begin
Application.OnException:=MyException;//挂上异常处理过程
end;
另外还要注意,尽量不要在界面层来校验数据,例如在button的click事件里写校 验代码。可以把它写成一个函数,放到数据层里。这样你的程序才层次分明,不 会因为改个字段名,而里里外外的去修改代码。Delphi的Datamodule窗口就是提 供给我们建立数据层用的。把和数据库有关的操作都尽量集中在这里是个好习惯 。
以上对数据校验简要介绍了一下。其实这里着重说的是校验的时机,具体的校验 代码视不同的表结构而不同。我对数据库的编程经验不多,错误之处,还请多多 赐教。
-- 共同探讨,共同提高.
※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.106.8.208]
|
|