虽然 Delphi 新推出了 DataSnap 模式的跨网络多层数据库框架,但我还是喜欢原来的基于 MIDAS 的多层数据库框架。如果要运行在 Internet 上,我更倾向于采用 WebService 架构下使用 MIDAS,这样比较少写代码。
进入正题。
MIDAS 框架下,从数据库到客户端是这样构成的:
1. FDConnection1 连接数据库;
2. FDQuery1 执行 select 语句获得表数据;
3. DataSetProvider1 连接 FDQuery1
4. ClientDataSet1 从 DataSetProvider1 获得数据;
5. Firebird 有一个生成器,产生新增的顺序编号;写一个存储过程从生成器获取这个编号;
5.1. FDStoredProc1 执行这个存储过程,让服务器端程序可以获得这个编号;
在客户端,新增一条记录时,不需要知道这个数据库的自增编号值。
1. ClientDataSet1 的 AfterInsert 事件里面,用代码填入负数编号作为替代(通常自增字段都是必须填写的,所以必须填入编号内容,因为客户端不知道数据库服务器真正插入记录后的编号会是多少);
procedure TForm1.ClientDataSet1AfterInsert(DataSet: TDataSet);
begin
ClientDataSet1.Tag := ClientDataSet1.Tag -1; //用 tag 来存储本地临时负数编号
with ClientDataSet1 do
begin
FieldByName('EMP_NO').AsInteger := ClientDataSet1.Tag;
end;
end;
2. 重点:设置 DataSetProvider1.Options 里面的 poPropogateChanges 为 True,这里默认是 False 的。有了这个设置,在服务器端修改记录后,会自动反馈到 ClientDataSet1而无需写代码。
3. DataSetProvider1 的 BeforeUpdateRecord 事件里面写代码将负数编号改为从数据库获得的正确自增编号:
procedure TForm1.DataSetProvider1BeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet; DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind;
var Applied: Boolean);
begin
//这里把提交过来的记录,如果是新增的记录,从数据库获得自增,替换掉
case UpdateKind of
ukModify: ;
ukInsert:
begin
DeltaDS.Edit;
DeltaDS.FieldByName('EMP_NO').NewValue := Self.GetEMPNo;
end;
ukDelete: ;
end;
end;
4. 其中, Self.GetEMPNo; 是利用存储过程获得数据库的生成器产生的自增编号:
function TForm1.GetEMPNo: Integer;
begin
FDStoredProc1.ExecProc;
Result := FDStoredProc1.Params[0].AsInteger;
end;
总结:
重点是设置 DataSetProvider1.Options 里面的 poPropogateChanges 为 True。这样在服务器端修改数据后,可以马上反应到客户端而无需写代码,无需去执行 ClientDataSet1.Refresh。