如何把“自由”ClientDataSet的数据更新到数据库?(300)

  • 主题发起人 主题发起人 fatalexception
  • 开始时间 开始时间
F

fatalexception

Unregistered / Unconfirmed
GUEST, unregistred user!
Borland给用户提供的标准三层结构用法是这样的:  客户端ClientDataSet -> 服务器端DataSetProvider -> Table/Query -> Database  客户端数据变化之后,只要ApplyUpdates就可以了。  但是,有时候不想这样绑定一串控件链,而想通过服务器端方法(即函数和过程的格式)自由读写数据。从服务器端读数据,只要把服务器端DataSetProvider.Data当作参数传递给客户端,再赋值到ClientDataSet.Data就可以了。  但是,向服务器端写数据,该如何实现呢?具体地说,客户端有一个“自由ClientDataSet”,也就是说,没有绑定服务器端DataSetProvider的ClientDataSet,只是在客户端运行时动态创建了字段结构,插入了记录,编辑了内容,现在想通过服务器提交到数据库中去。当然,数据集结构是与数据库表结构完全一致的。程序该如何实现呢?  注意,DataSetProvider的Data属性是只读的,因此只能让ClientDataSet.Data从DataSetProvider.Data里取值,却不能用ClientDataSet.Data给DataSetProvider.Data赋值。
 
服务端加一个方法接收客户端传入的DataSetProvider.Data,然后在服务端把数据post到数据库
 
上面说错了,是传入ClientDataSet.Data
 
回aikede:  客户端可以把ClientDataSet的Data属性(数据包)通过服务器端方法传递到服务器端,但问题是传递给服务器端的什么对象呢?或者说,服务器端由什么对象负责接收这个数据包呢?“在服务端把数据post到数据库”又是靠什么对象来做呢?
 
data保存的是更新后的数据,也即结果。delta里面保存的才是更新的操作LOG,把这个传过去,就可以更新了。
 
用ClientDataSet的XMLData
 
to levi: 问题是,传给谁呢?服务器端的哪个对象(或者说哪种控件)可以接受Delta数据包并将其更新到数据库呢?
 
思路很简单,客户端的ClientDataSet.Data或者Delta就是数据包,把它传给服务器,再由服务器更新到数据库就可以了。但问题是,服务器端的哪个对象可以完成这个任务?
 
1、客户端的ClientDataSet.Delta 传给客户端的自由ClientDataSet.data 2、然后客户端的自由ClientDataSet.XMLData 传给服务器 的自由ClientDataSet.XMLData3、DataSetProvider.ApplyUpdates(服务器的自由ClientDataSet.Data
 
1将ClientDataSet.Delta作为参数远程调用服务端的某个方法如:procedure UpdateData(variant*):stdcall(自己去找想办法生成该方法)。将Delta传到远程电脑。2在服务端的UpdateData方法中分析Delta中的数据,根据记录新增、修改、删除状态处理。
 
to 宋阳: 服务器端的DataSetProvider本身是不能向数据库更新数据的吧,还是要有数据集控件吧?具体这一环节如何实现呢?
 
to chinasky132: 你的意思是,把打好包的数据再拆成一个一个的整型、实型、字符串、布尔型……变量,再用循环语句Insert或Update到数据库中?
 
chinasky132:[^]
 
楼主的想法是完全可以实现地,比如,QuickBurro里就有这样的方法提交Cds的Delta数据:SyncBurro1.ApplyCdsUpdates(TargetNodeId,TableName,KeyFieldList,Cds.Delta);把Cds的Delta数据提交到远程节点(TargetNodeId)的数据表(TableName)中,表的记录唯一性关键字段由KeyFieldList变量指定,比如:SyncBurro1.ApplyCdsUpdates('金华#浙江快客','BusLog','LineId,BusId',ClientDataset1.Delta);
 
客户端函数function PostModifyInfo(aTableName,aIndexName:String;aData:Variant):Boolean;var vByte:TByteDynArray;
msByte:TMemoryStream;
I,J,aFlag,aInsertFlag,apicFlag:Integer;
aSqlStr,Id,aSqlStrAll,aIdNew,aStrFiled:String;
tmpClient :TClientDataSet;
begin
try Result := False;
if VarIsEmpty(aData) then
Exit;
tmpClient := TClientDataSet.Create(nil);
apicFlag := 0;
msByte:=TMemoryStream.Create;
try tmpClient.Data := aData;
tmpClient.Active := not tmpClient.IsEmpty;
if tmpClient.Active then
begin
aSqlStrAll := 'begin
';
aInsertFlag := 0;
for I := 0 to tmpClient.RecordCount -1do
begin
aFlag := 0;
aSqlStr := '';
aStrFiled := '';
case tmpClient.UpdateStatus of usUnmodified: begin
aFlag := 1;
Id :=tmpClient.FieldByName(aIndexName).AsString;
end;
usModified: begin
aSqlStr := 'update '+aTableName+' set ';
for J := 0 to tmpClient.FieldCount-1do
begin
if not tmpClient.Fields[J].IsNull then
if tmpClient.Fields[J].DataType <> ftBlob then
aSqlStr :=aSqlStr+tmpClient.Fields[J].FieldName+'='''+tmpClient.Fields[J].AsString+''',' else
begin
apicFlag := 1;
TBlobField(tmpClient.Fields[J]).SaveToStream(msByte);
setlength(vByte,msByte.size);
msByte.position:=0;
msByte.read(vByte[0],msByte.size);
aSqlStr :=aSqlStr+tmpClient.Fields[J].FieldName+'=:Id,';
end;
end;
Delete(aSqlStr,Length(aSqlStr),1);
aSqlStr :=aSqlStr+' where '+aIndexName+' = '''+Id+''';';
end;
usInserted: begin
for J := 0 to tmpClient.FieldCount-1do
begin
aStrFiled := aStrFiled +tmpClient.Fields[J].FieldName+',';
if UpperCase(tmpClient.Fields[J].FieldName) = UpperCase(Trim(aIndexName)) then
begin
aSqlStr :=aSqlStr+'GetTbIndex('''+aTableName+''','''+aIndexName+''','+IntToStr(tmpClient.FieldByName(aIndexName).Size)+'),' end else
begin
if tmpClient.Fields[J].DataType <> ftBlob then
aSqlStr :=aSqlStr+''''+tmpClient.Fields[J].AsString+''',' else
begin
if not tmpClient.Fields[J].IsNull then
begin
apicFlag := 1;
TBlobField(tmpClient.Fields[J]).SaveToStream(msByte);
setlength(vByte,msByte.size);
msByte.position:=0;
msByte.read(vByte[0],msByte.size);
aSqlStr :=aSqlStr+':Id'+',';
end else
aSqlStr :=aSqlStr+''''+tmpClient.Fields[J].AsString+''',';
end;
end;
end;
Delete(aStrFiled,Length(aStrFiled),1);
Delete(aSqlStr,Length(aSqlStr),1);
aSqlStr := 'insert into '+aTableName+' ( '+aStrFiled+') values('+aSqlStr+');
';
aInsertFlag := aInsertFlag +1;
end;
usDeleted: begin
aSqlStr := aSqlStr+'delete from '+aTableName+' where '+aIndexName+' = '''+tmpClient.FieldByName(aIndexName).AsString+''';';
end;
end;
tmpClient.Next;
if aFlag = 0 then
aSqlStrAll := aSqlStrAll +aSqlStr;
end;
aSqlStrAll := aSqlStrAll + ' end;
';
if apicFlag > 0 then
Result := pubExecSqlP(aSqlStrAll,vByte) else
Result := pubExecSql(aSqlStrAll);
end else
begin
Result := False;
end;
finally tmpClient.Free;
msByte.Free;
end;
except if tmpClient <> nil then
tmpClient.Free;
if msByte <> nil then
msByte.Free;
Result := False;
end;
end;
服务端函数var PubQury:TADOQuery;
begin
try try PubQury := TADOQuery.Create(nil);
if AlinkStr = '' then
AlinkStr := 'Provider=MSDAORA.1;Password=''xxx'';User ID=''XXX'';Data Source=ORACLE;Persist Security Info=True';
PubQury.ConnectionString := AlinkStr;
PubQury.SQL.Text := AsqlStr;
PubQury.ExecSQL;
finally PubQury.Free;
end;
Result := true;
except on e:Exceptiondo
begin
Result := False;
end;
end;
end;
给分吧!!
 
来自:chinasky132, 时间:2010-10-29 0:45:34, ID:4002199这位兄弟说的就可以了。。至于服务器端如何解析Delta到数据库中,可以自己自定义解析,百度里有,也可以由DataSetProvider.ApplyUpdates()解决,需要自己想点办法。
 
如果还要把Delta拆成一个一个的记录、一个一个的字段,人工拼凑Insert、Delete、Update,那么这个问题就不值300分了。我的第一反应也是在服务器端构造循环、拼凑SQL,但记录锁、表锁、取值约束、主键约束、重复记录、更新顺序等问题都让人“如履薄冰”“心惊胆战”。而且Midas提供了整套的解决方案。所以我还是希望借助Midas自己的代码来完成提交的功能。
 
后退
顶部