代码如下:
  try
    FPurchase.Connection.BeginTrans;
    FPurchase.Save;                      //1
    FPurchaseDetail.Save;                //2
    FPurchase.Connection.CommitTrans;
  except
    FPurchase.Connection.RollbackTrans;
    on e: Exception do
    begin
      StatuseInfo(Caption + ':' + e.Message);
    end;
  end;FPurchase和FPurchaseDetail用的同一个ADOConnection;
1,2位置的Save方法都是使用的DataSet.UpdateBatch;问题:
当代码1的保存成功,代码2的保存出现异常回滚的时候,如果用户修改FPurchaseDetail中的数据,再次保存,则代码2处的保存成功,代码1处的保存不会出现异常,但是实际上数据没有能够存入数据库。个人考虑:
当第一次保存的时候,因为代码1的保存没有出现异常DataSet的状态发生变化,应该变成了浏览状态。
第二次保存时,因为1位置的DataSet已经是浏览状态,而且没有发生变化所以不再保存。而仅仅执行代码2,将明细保存了。不知是否正确,尝试了一些方法,觉得不妥,是否有更好的方法,大家讨论,谢谢

解决方案 »

  1.   

    自己顶一个,还是用Delphi的人少了啊?
      

  2.   

    FPurchase.Connection.RollbackTrans;
    这个代码应该在异常内部,上面写的有点小问题,但是不影响讨论啊
      

  3.   

    D的事务是针对adoConnection的,  只要2个DataSet连的是同一个adoConnection那
    adoConnection.BeginTrans;
    adodataset1.UpdateBatch();
    adodataset2.UpdateBatch();


    adoConnection.CommitTrans; 只要中间有异常  都会回滚
      

  4.   

    第一次大家都会回滚,但是,第二次的时候就不一样了,因为更正了明细上的数据,所以明细是可以提交的,但是主表由于第一次已经提交,state已经是浏览,所以不会再次提交。而且修改之后也不能提交!
      

  5.   

    都会提交上去的procedure TForm1.Button1Click(Sender: TObject);
    begin
      adoconnection1.BeginTrans;
      try
        adodataset1.UpdateBatch();
        if adodataset2.FieldByName('ProductID').AsString='' then
          raise exception.Create('ProductID not null');
        adodataset2.UpdateBatch();
        adoconnection1.CommitTrans;
      except
        adoconnection1.RollbackTrans;
      end;
    end;
      

  6.   

    to china618 上面的代码是我写的不大好,你说的是对的
    to kaper 你的代码如果继续修改adodataset2里面的数据直到满足要求,第二次提交的时候稍adodataset1是会提交的,但是,数据没有写到数据库,因为现在sataset的状态是UnModified,这个问题其实很多人发现了,只是现在好像没有人继续讨论了,我就问问,是不是大家都已经有了解决的方法了?http://www.delphibbs.com/delphibbs/dispq.asp?lid=2090654
    下面有很长的讨论,大家可以看看,保存文件据说很好,不过如果操作的表超过2个,保存文件也有点力不从心了下面是一个方法,但是我认为没有实际上解决问题
    http://www.01cn.net/cgi-bin/threaded_show.cgi?tid=2332&h=1&bpg=1&age=0
      

  7.   

    我试过了  只要修改后 if   adodataset2.FieldByName( "ProductID ").AsString= " "   then 满足了这个条件  就可以提交上去了  2个表都提交上去的  是一起提交的
      

  8.   

    CREATE TABLE [Master] (
    [ID] [int] IDENTITY (1, 1) NOT NULL ,
    [BillNo] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
    CONSTRAINT [PK_Master] PRIMARY KEY  CLUSTERED 
    (
    [ID]
    )  ON [PRIMARY] 
    ) ON [PRIMARY]
    GO
    CREATE TABLE [Detail] (
    [ID] [int] IDENTITY (1, 1) NOT NULL ,
    [BillID] [int] NULL ,
    [ProductID] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
    [A] [int] NULL ,
    [B] [int] NULL ,
    [C] AS ([A] - [B]) ,
    CONSTRAINT [PK_Detail] PRIMARY KEY  CLUSTERED 
    (
    [ID]
    )  ON [PRIMARY] 
    ) ON [PRIMARY]
    GO你自己先试试看嘛
      

  9.   

    to kaper :
    我已经尝试了很多次,这个问题已经困扰了我很久了,相信不是我一个人有这样的问题。你的代码是有问题的!你的判断只是对数据本身的判断,我明白你的意思,就是对所有用户输入的数据进行验证,只有全部符合数据库的约束和规则才能提交。可是就算所有的数据都能够满足验证,adodataset2.UpdateBatch(); 这一行代码还是可能发生异常的!!比如你在明细选择的产品很可能有其他人已经删除了,这个时候客户端的验证是可以满足的,但是当你提交数据的时候确违背了外键约束,在这种情况下发生异常的时候回滚,如果更换了另一个产品再提交的时候adodataset1.UpdateBatch(); 是不会有任何数据保存的!!应该还是DataSet的状态变成了UnModified,无法回到历史状态造成的。不知道我说的是否清晰,感谢kaper。
      

  10.   

    这种处理没有写过,不过我可以提意另辟蹊径
    adodataset1,adodataset2的recordset取其变化值
    再合成SQL回写数据库。自己来处理生成SQL
    其实updateBatch也是一样的合成SQL,只不过有一个属性,如果设置成严格更新,
    会把所有的字段值当成条件来更新,为避免出现更新覆盖。
    ===
    分享快乐:www.delphichm.com
      

  11.   

    to:21ithorse 应该是比较可靠,不过很麻烦,如果写好了生成SQL代码的类,以及执行SQL命令的方法,也还可以,属于一劳永逸的方法.我现在是这样处理的:
    不使用批提交方式,新建单据的时候(这个问题主要出现在新建的时候),同时新建一个明细数据,在明细DataSet的BeforePost事件中提交单据头.