我做了一个midas的程序结构如下(很简单):有表(ACCESS)
主表:a('项目编码'为主键)
工资项目编码  项目名称  
   1011       x1
   1012       x2
   1013       x3
   1014       x4
子表: b('人员ID','项目编码',为主键)
人员ID  工资项目编码  金额
P101     1011          50   
P101     1012          50
P101     1013          80 
P101     1014          90
服务端access->ADO->Provider1 (updatemode:=upwhereall)
客户端DCOMConnection1->ClientDataSet1->DataSource1->DBGrid1在客户端有码如下
首先通过ClientDataSet取得一个视图
begin
 ClientDataSet1.Close;
 ClientDataSet1.CommandText:=' SELECT b.工资项目编码,b.人员ID,a.项目名称,b.金额 ';
 ClientDataSet1.CommandText:=ClientDataSet1.CommandText+'  from a  inner join b on a.工资项目编码=b.工资项目编码';
 ClientDataSet1.CommandText:=ClientDataSet1.CommandText+' where  b.人员ID='P101';
 ClientDataSet1.Open ;
end;
视图如下:
人员ID  工资项目编码 项目名称    金额
P101     1011          x1         50   
P101     1012          x2         50
P101     1013          x3         80 
P101     1014          x4         90
其次通过在DBGrid中修改'金额'
然后保存代码如下:
 begin
  if ClientDataSet1.ChangeCount>0 then
    begin
     ClientDataSet1.ApplyUpdates(-1);
     if ClientDataSet1.ChangeCount>0 then
                          begin
                          application.MessageBox('保存失败','错误',  MB_ICONSTOP);
                          exit;
                          end;
    application.MessageBox('保存成功','提示',  MB_ICONINFORMATION);
    end
 else showmessage('没有数据需要保存');
 end;但是每次当我保存修改时
都会出现'保存失败';
请问这是为什么?
还有就是如果我把Provider1的updatemode设置upWhereChanged后,保存修改时则出现'保存成功',但会把所有金额相同的记录全部修改.
真是搞不懂,我应该怎样做才能正确保存数据呢?望高手指点一下!谢谢!

解决方案 »

  1.   

    begin
      if ClientDataSet1.ChangeCount >0 then
        begin
         ClientDataSet1.ApplyUpdates(-1);
         ClientDataSet1.Refresh;//这里重新刷新试试
         if ClientDataSet1.ChangeCount >0 then
                              begin
                              application.MessageBox( '保存失败 ', '错误 ',  MB_ICONSTOP);
                              exit;
                              end;
        application.MessageBox( '保存成功 ', '提示 ',  MB_ICONINFORMATION);
        end
     else showmessage( '没有数据需要保存 ');
     end; 
      

  2.   

    to Delphi(Pascal) code
    实际上执行"ClientDataSet1.ApplyUpdates(-1)"后就没有把数据写进数据库,所以ClientDataSet1.Refresh是没用的,
    如果我把Provider1的updatemode设置upWhereChanged后,修改的数据可以写进后台数据库,就是会把相同其他记录全部一起修改了,这是为什么啊!是不是需要在ClientDataSet1返回的视图中重新指定关键字段,可我不知道怎样指定!
         
      

  3.   

     begin
      if ClientDataSet1.ChangeCount >0 then
        begin
         ClientDataSet1.ApplyUpdates(0); //不要用-1,用0.代表有错误就不保存,数据有保障
         //如果数据的确保存进了数据库,用
         //ClientDataSet1.MergeChangeLog;
         //合并数据库和本地的数据.
         if ClientDataSet1.ChangeCount >0 then
                              begin
                              application.MessageBox( '保存失败 ', '错误 ',  MB_ICONSTOP);
                              exit;
                              end;
        application.MessageBox( '保存成功 ', '提示 ',  MB_ICONINFORMATION);
        end
     else showmessage( '没有数据需要保存 ');
     end; 
      

  4.   

    to lvloj 
    虽然每次都显示(按你的代码)"保存成功",可就是没有把数据写进后台数据库?我的关键问题是如何更新数据,
    难道在clientdataset中就无法更新连表查询的结果吗?可是直接用adoquery都可以实现啊!真是搞不懂?
      

  5.   

    这种Join几个表的SQL,如果需要Update成功,就在中间层Provider1的Onupdate事件上自己编写代码。否则直接用ClientDataSet的ApplyUpdates是无效的。目前我这里没有现成的代码,也没有环境。你搜索一下论坛或者Google,或者参考李维的书籍。
      

  6.   

    to chinasg  
    能给个列子吗?
      

  7.   

    设置服务器端的属性
      DataSetProvider.ResolveToDataSet := True;
      

  8.   

    如lvloj所说,先设定Provider的ResolveToDataSet:=True,
    然后在中间层 连接provider的ADODataset的OnApplyRecord事件中编写代码.同时增加一个UpdateDataset,执行
    更新、添加等动作.
    自己添加事件之后,在客户端,你还是直接调用ClientDataset的Applyupdates。由于我后台是Oracle数据库,连接数据库的控件是DOA,所以才会有DeclareQueryVariables的函数,
    你针对自己的环境,修改一下。下面的代码给你做一个参考。
    procedure TdmEngServer.odEDMApplyRecord(Sender: TOracleDataSet;
      Action: Char; var Applied: Boolean; var NewRowId: String);
    var
      Call:String;
    begin
      case Action of
        'U': Call := 'MFG_PKG_EDM_Update.UpdateRecord(:autoreport,:hardcopy,:recipe,:faultcode,:faultmessage,'
                  +':affectwaferid,:reworkwaferid,:reworkcode,:reowrked,:disposition,:smif,:chb,:slot,:handissue,'
                  +':keyin,:module,:EDMTYPE,:edmno,:RECOVERYRUNCARD,:RECOVERYACTION,:lotids,:Partid,'
                  +':stage,:ReleaseToModule,:highlight)';
      else
        Call := '';
      end;
      // Build a PL/SQL block with a call to a MFG_PKG_EDM_Update procedure;
      if Call <> '' then
      begin
        with updateEDM do
        begin
          Clear;
          SQL.Add('begin');
          SQL.Add('  ' + Call + ';');
          SQL.Add('end;');
          // Declare the variables
          Sender.DeclareQueryVariables(updateEDM);
          // Set the values of the variables
          Sender.SetQueryVariables(updateEDM);
          // Execute the query
          Execute;
        end;
      end;
      // Notify to the dataset the we have applied the record
      Applied := True;
      

  9.   

    to chinasg 
     Call :=  'MFG_PKG_EDM_Update.UpdateRecord(:autoreport,:hardcopy,:recipe,:faultcode,:faultmessage, ' 
                + ':affectwaferid,:reworkwaferid,:reworkcode,:reowrked,:disposition,:smif,:chb,:slot,:handissue, ' 
                  + ':keyin,:module,:EDMTYPE,:edmno,:RECOVERYRUNCARD,:RECOVERYACTION,:lotids,:Partid, ' 
                  + ':stage,:ReleaseToModule,:highlight) '; 
    --------------------------------------------------------
    上面这段是什么意思啊!
    我是用ado连接数据库的.
    adoquery中没有OnApplyRecord事件?
    其次UpdateDataset是不指UpdateSQL,还是另外一个adoDataSet?
    请指教,谢谢!
      

  10.   

    Call:=其实只是一句SQL而已,因为我把Update的代码写成Oracle的存储过程,所以把参数传入,用存储过程更新数据。
    UpdateDataSet你可以用UpdateSQL,也可以用AdoDataSet,
    把call换成你自己SQL,比如call:='Update Test_table set TestField=:aaa where ID=:BBB';
    然后把call 赋值给你的UpdateDataset.我对Adoquery不是很了解,没有用过,如果没有OnApplyrecord这个事件,应该也有相关事件,或者用adodataset替代也是可以。
      

  11.   

    to chinasg 
    你的意思是不时通过updateDateset中写'update......'语句来更新数据库;
      

  12.   

    to 楼上的各位
    我有点不解:我把Provider1 (updatemode:=upwherekeyonly),ResolveToDataSet:=True.
    begin 
    ........
    ClientDataSet1.open
    ClientDataSet1.fieldbyname(人员ID).proiderflags=[pfInupdate,pfInwhere,pfInkey];
    ClientDataSet1.fieldbyname(工资项目编码).proiderflags=[pfInupdate,pfInwhere,pfInkey];
    end;
    然后用ClientDataSet1的ApplyUpdates(0).
    提示"Unable to find record No key specified"
    为什么会出现这种提示呢?请各位指教!
      

  13.   

    to 楼上的各位!
    问题终于解决了!还是多看help有用啊!