有没有人回答我啊,我挂了两天,没人理我,关于MIDAS中主从表更新的问题,分不够另加 (300分)

  • 主题发起人 主题发起人 苟延残喘
  • 开始时间 开始时间

苟延残喘

Unregistered / Unconfirmed
GUEST, unregistred user!
如题:
我在客户端得到一个数据集,是JOIN出来的,到服务器端,我怎么样在DataSetProvider
的beforupdaterecord事件中对服务器的数据库更新。急,
 
斑竹有没有空,给个答案吧,
 
这是我做的一个项目的简化示例,希望对你有用
ACCESSPOINT为主表:字段为POSNO、POSNAME,POSNO为主键,
COLLECTORCNT为从表:字段为POSNO、CNT
置DataSetProvider.ResolvetoDataset := False;
procedure TUserDataInterface_MA.ExecuteSQL(S: string);
begin
with cdsExecuteSQLdo
begin
CommandText := S;
if CommandText = '' then
Exit;
try
Execute;
except on E:Exceptiondo
begin
//HandleException('执行SQL时出错:'+E.Message);//错误处理
raise;
end;
end;
end;
end;

procedure TUserDataInterface_MA.CommonBeforeUpdateRecord(DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind;
KeyFieldName: array of string);
var
i: Integer;
begin
if UpdateKind <> ukInsert then
for i := Low(KeyFieldName) to High(KeyFieldName)do
DeltaDS.FieldByName(KeyFieldName).ProviderFlags := DeltaDS.FieldByName(KeyFieldName).ProviderFlags + [pfInKey];
end;

procedure TUserDataInterface_MA.dspCentralizerBeforeUpdateRecord(
Sender: TObject;
SourceDS: TDataSet;
DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind;
var Applied: Boolean);
var
sSQL: string;
i: Integer;

begin
//设置主键的pfInKey标志
CommonBeforeUpdateRecord(DeltaDS, UpdateKind, ['POSNO']);
try
try
with DeltaDSdo
case UpdateKind of
ukInsert:
with cdsExecuteSQLdo
//TClientDataSet
begin
sSQL := 'INSERT INTO ACCESSPOINT VALUES(''' + FieldByName('POSNO').AsString + ''','''
+ FieldByName('POSNAME').AsString + ''')';
ExecuteSQL(sSQL);
sSQL := 'INSERT INTO COLLECTORCNT VALUES(''' + FieldByName('POSNO').AsString + ''','
+ FieldByName('CNT').AsString + ')';
ExecuteSQL(sSQL);
end;
ukModify:
begin
//从表更新
if not VarIsEmpty(FieldByName('CNT').NewValue) then
//未被更新的字段(VarIsEmpty = True)值不被传回AppSvr
begin
sSQL := 'UPDATE COLLECTORCNT SET CNT = :CNT WHERE POSNO = :OLDPOSNO';
with cdsExecuteSQLdo
begin
CommandText := sSQL;
Params.ParamByName('CNT').Value := DeltaDS.FieldByName('CNT').NewValue;
Params.ParamByName('OLDPOSNO').Value := DeltaDS.FieldByName('POSNO').OldValue;
Execute;
end;
end;

//主表更新
sSQL := '';
for i := 0 to FieldCount - 1do
if Fields.FieldName <> 'CNT' then
//not include field CNT
if not VarIsEmpty(Fields.NewValue) then
sSQL := sSQL + Fields.FieldName + '=:' + Fields.FieldName + ',';
if sSQL = '' then
Exit;
System.Delete(sSQL, Length(sSQL), 1);//delete last ','
sSQL := 'UPDATE ACCESSPOINT SET ' + sSQL + ' WHERE POSNO = :OLDPOSNO';
with cdsExecuteSQLdo
begin
CommandText := sSQL;
for i := 0 to DeltaDS.FieldCount - 1do
if DeltaDS.Fields.FieldName <> 'CNT' then
//not include field CNT
if not VarIsEmpty(DeltaDS.Fields.NewValue) then
Params.ParamByName(DeltaDS.Fields.FieldName).Value := DeltaDS.Fields.NewValue;
Params.ParamByName('OLDPOSNO').Value := DeltaDS.FieldByName('POSNO').OldValue;
Execute;
end;
end;
ukDelete:
begin
//先删除从表,再删除主表,另外,可用触发器实现级联删除
//我在Interbase中测试,此处2条SQL语句将自动放在一个事务中
sSQL := 'DELETE FROM COLLECTORCNT WHERE POSNO = ''' + FieldByName('POSNO').AsString + '''';
ExecuteSQL(sSQL);
sSQL := 'DELETE FROM ACCESSPOINT WHERE POSNO = ''' + FieldByName('POSNO').AsString + '''';
ExecuteSQL(sSQL);
end
end;
finally
Applied := True;
end;
except
Applied := False;
end;
end;

//.........
initialization
TComponentFactory.Create(ComServer, TUserDataInterface_MA,
Class_UserDataInterface_MA, ciMultiInstance, tmApartment);
end.
 
to labelsoft
哥们儿,咱俩写的基本一样,但我总担心会出现问题,因为事物的问题,李维说能自动
支持事物,但我有点担心,谢谢支持。毕竟我等了这么长时间,你是第一个回答我的。
请大家继续讨论。
 
来个笨点的办法,在BeforeUpdateRecord中解析DeltaDS,生成sql更新数据库,我就这么干过,别笑哦 :)
 
>迷糊
我也这么干啊
>labelsoft
procedure TUserDataInterface_MA.ExecuteSQL(S: string);

procedure TUserDataInterface_MA.CommonBeforeUpdateRecord(DeltaDS:TCustomClientDataSet;
UpdateKind: TUpdateKind;
KeyFieldName: array of string);
这两个过程都是自定义的接口函数吗?
CommonBeforeUpdateRecord中的KeyFieldName参数怎么传呢?是ClientDataSet的fields吗?
 
我怎么样在DataSetProvider的beforupdaterecord事件中对服务器的数据库更新。
为什么不用控件直接更新好了!
 
to hongxing_dl:
这两个过程都是自定义的接口函数吗?
>这两个过程是自定义的私有函数,不是接口函数,本地自己用
CommonBeforeUpdateRecord中的KeyFieldName参数怎么传呢?是ClientDataSet的fields吗?
>如CommonBeforeUpdateRecord(DeltaDS, UpdateKind,['FieldName1','FieldName2',...]);是表各字段名,一般为主键或唯一索引
 
我有三个表(固定资产主表gdzcm(gzh char(10)主键,gsdm char(2),rq datetime,jsr char(10)经手人,note varchar(50)备注);从表gdzcd(gzh char(10),kmdm char(12)科目代码,sl
numicer (9,2)数量),dj numicer(9,2)单价,jzr numicer (9,2)折旧率,note varchar(50))
科目表(kmdm char(12),kmmc varchar(60)科目名称,dw char(4)单位)
这三个表用三层开发如何实现这种主从表的输入服务器怎样更新主从表的数据
客户端界面:
公司代码:(输入) 时间:(输入) 经手人:(输入) 固定资产号:
备注:(输入)
------------------------------------------------------------------------------
科目代码 种目名称 数量 单价 折旧率 备注
5100.001.001 电脑设备 15 3000 0.10
....
--------------------------------------------------------------------------------
新增 保存 删除 列印 关闭
希望各位用过三层开发的富翁能给我一个demo,我很想学习多层开发?
e_mail:jesse1219@21cn.com或jesse_zhou_1219@163.com
先在些多谢了!
 
to:迷糊,hongxing_dl,楼主:
本人初学Delphi,前辈们能不能给个例子,说明一下,前端Join出来的一个数据集,
在后台DataSetProvider的BeforeUpdateRecord中解析DeltaDS,如何生成sql更新数据库?
盼回音。

to 楼主:
解决问题时,别忘了把答案公布出来,我可以贡献出部分分来给回答者。



 
李生的那本書有不是有例子嗎?不過他的是D5,我在D7上試,發現BeforeUpdateRecord事件中多了一個參數,試驗失驗,所以也想知道答案。
 
我做了,DELETE和UPDATE都行,就是INSERT不行
unit Unit2;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
Windows, Messages, SysUtils, Classes, ComServ, ComObj, VCLCom, DataBkr,
DBClient, Project2_TLB, StdVcl, DB, DBTables, Provider,StrUtils,Variants,Unit1;
type
TZJMTUServer = class(TRemoteDataModule, IZJMTUServer)
DataSetProvider1: TDataSetProvider;
Database1: TDatabase;
Query1: TQuery;
UpdateSQL1: TUpdateSQL;
UpdateSQL2: TUpdateSQL;
ClientDataSet1: TClientDataSet;
DataSource1: TDataSource;
procedure DataSetProvider1BeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet;
DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind;
var Applied: Boolean);
private
{ Private declarations }
protected
class procedure UpdateRegistry(Register: Boolean;
const ClassID, ProgID: string);
override;
public
{ Public declarations }
procedure SetParams(CUpdateSQL:TUpdateSQL;CDeltaDS: TCustomClientDataSet;CUpdateKind:TUpdateKind);
end;

implementation
{$R *.DFM}
class procedure TZJMTUServer.UpdateRegistry(Register: Boolean;
const ClassID, ProgID: string);
begin
if Register then
begin
inherited UpdateRegistry(Register, ClassID, ProgID);
EnableSocketTransport(ClassID);
EnableWebTransport(ClassID);
end else
begin
DisableSocketTransport(ClassID);
DisableWebTransport(ClassID);
inherited UpdateRegistry(Register, ClassID, ProgID);
end;
end;

procedure TZJMTUServer.SetParams(CUpdateSQL:TUpdateSQL;CDeltaDS: TCustomClientDataSet;CUpdateKind:TUpdateKind);
var
i:integer;
PName:string;
Field:TField;
begin
if not assigned(CUpdateSQL.DataSet) then
exit;
with CUpdateSQL.Query[CUpdateKind]do
begin
for i:=0 to Params.Count-1do
begin
PName:=MidStr(Params.Name,5,Length(Params.Name)-4);
Field:=CDeltaDS.FindField(PName);
if not Assigned(Field) then
continue;
Case CUpdateKind of
ukInsert:
begin
Form1.StatusBar1.Panels[1].Text:='Inserting....';
if VarIsEmpty(Field.NewValue) then
Params.AssignFieldValue(Field,Field.CurValue)
else
Params.AssignFieldValue(Field,Field.NewValue);
end;
ukDelete:
begin
Form1.StatusBar1.Panels[2].Text:='Deleteing....';
Params.AssignFieldValue(Field,Field.OldValue);
end;
ukModify:
begin
Form1.StatusBar1.Panels[3].Text:='Updating....';
if MidStr(Params.Name,1,4)='OLD_' then
Params.AssignFieldValue(Field,Field.OldValue)
else
begin
if VarIsEmpty(Field.NewValue) then
Params.AssignFieldValue(Field,Field.OldValue)
else
Params.AssignFieldValue(Field,Field.NewValue);
end;
end;
end;
end;
end;
end;

procedure TZJMTUServer.DataSetProvider1BeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet;
DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind;
var Applied: Boolean);
begin
ClientDataSet1.Data:=DeltaDS.Data;
Form1.StatusBar1.Panels[0].Text:='Start....';
Query1.UpdateObject:=UpdateSQL1;
SetParams(UpdateSQL1,DeltaDS,UpdateKind);
UpdateSQL1.ExecSQL(UpdateKind);
Query1.UpdateObject:=UpdateSQL2;
SetParams(UpdateSQL2,DeltaDS,UpdateKind);
UpdateSQL2.ExecSQL(UpdateKind);
Applied:=true;
end;

initialization
TComponentFactory.Create(ComServer, TZJMTUServer,
Class_ZJMTUServer, ciMultiInstance, tmApartment);
end.
不过在CDeltaDS.DATA有插入的数据,还在苦思当中
 
找一下 李大俠那本系統篇看一下Delta的結構就知道怎麼用什麼來解釋它了。
用BDE多表更新的確有點麻煩。 ADO就方便多了,可以自動更新(SQL語句要寫好);
 
多谢大家的帮忙,我也正在实验,不过这两天在忙着写别的模块。这几天开始动手测试。
我第一步可能要把更新和插入写成存储过程,期待大家继续讨论。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部