zoukankan      html  css  js  c++  java
  • ADO BUG之'无法为更新定位行....' 解决之道

     最近正在做BDE移植ADO工作,遇到很多BDE不曾有过的问题,通过网上找资料和研究。得出以下解决方案:

    引自:http://www.delphibbs.com/keylife/iblog_show.asp?xid=29098
    Delphi中,如果使用ADOQuery插入数据没有问题, 之后对数据进行修改保存时,就会遇到无法为更新定位行,一些值可能已在最后一次读取后已更改的问题。

    原因有这样几种:

    1.
    在数据库设计时,为某些字段设置了默认值,在修改进行提交以后,数据库会自动修改对应字段的所有行的默认值,从而导致了数据库与数据集中数据的不一致,使ADOQuery无法对数据集进行定位。

    2.
    数据库对应的表没有主键,输入了重复的数据以后,数据库里有两条一样的数据,从而使ADOQuery无法对数据进行定位。

    解决方法:

    1.
    修改数据库设计,不再设置默认值,为数据库表定义主键,保证其唯一性。

    2.
    在执行完ADOQuery.Post之后,执行ADOQuery.Refresh,对于设置默认值的情况可以解决。
     (refresh
    dataset中的默认值字段获得了值,跟数据库中一致了)

    3.
    改用Insert into sql语句插入,而不是add--post方式. 但这种方式不更新其他打开该表的query, 所以要requery才行, refresh不起作用.

    --------------------------------------------------------------------------
    外一篇关于oracle中出现该问题的文章:
    分析解决delphibug无法为更新定位行。一些值可能已在最后一次读取后已更改。

       Delphi
    在使用ADO操作oracle数据库时,经常会出现无法为更新定位行。一些值可能已在最后一次读取后已更改。的错误,一直没有找到好的解决办法,但同样得代码在SQLServer上却没有问题。上回看到了eygle 如何跟踪oracle的文章有所启发,对程序的数据库操作进行了跟踪,找到了问题的所在。


    分析错误出现的情况

    1.   
    在使用DBGrid对表进行编辑时,添加一行数据,再修改新添加行中的原来为空的一个字段(文本型),改变光标到其它行,此时提示错误。

    分析:添加不报错,修改提交时报错,分析可能是执行UPDATE时报错。

    2.   
    对一条数据中文本字段进行第二次修改时提示同样错误。

    分析:第一次修改不报错,第二次就报错,两次都是执行UPDATE,区别可能就是,第一次和第二次的一些状态不同了。


    跟踪ORACLE,得到执行错误时的脚本

    UPDATE "
    测试" SET "档号"=:V00001 WHERE "档号"=:V00002 AND

    "ROWID"=:V00003

    Bind#0

     value="eee"

    Bind#1



    Bind#2

    value="AAAD7CAAGAAACgPAAI"



    跟踪ORACLE,得到执行正确时的脚本

    UPDATE "
    测试" SET "档号"=:V00001 WHERE "档号" IS NULL AND "ROWID"=:V00002

    Bind#0

     value="eee"

    Bind#1

     value="AAAD7CAAGAAACgPAAI"



    根据以上跟踪的结果,找到了问题的所在,"档号"=’’ "档号" IS NULL ORACLE是不同的, "档号"=’’ORACLE 不能定位到正确的记录行,所以造成了更新的失败。

    我们知道ORACLE中文本型字段有两种状态 NULL NOT NULL,而MSSQL中有三种状态 NULLNOT NULL ’’ ,这就是为何以上程序在MSSQL中运行正常,而在ORACLE中却不能正常的原因了。(注:Oracle中如设置一个文本字段=’’Oracle会自动将其转换为NULL,但是在查询时如果这样用就不行,不知能不能算是ORACLE的一个BUG)

    为何在第一次编辑时能正确生成代码,而在第二次就不可以了。原因就是Delphi中的TField的属性IsNULL,第一次其从数据库中取出了正确的状态为IsNull=True,编辑之后,如果数值=’’,其IsNull就是False,而TAdoQuery生成更新脚本时就是根据这个属性来生成=’’ IS NULL这两种脚本的。

    找到问题,我们就可以写代码来解决问题了。分析以上问题,我们只要在使用ORACLE数据库时,在提交前,将文本字段=’’字段的IsNull=True,就可以了,我们在TADOQueryBeforePost事件中添加代码,代码如下:

    procedure TFrmData.adoqMainBeforePost(DataSet: TDataSet);

    var

     i: Integer;

    begin

     if DATA = 'ORACLE' then //
    自定义,标明数据库类型

      for i := 0 to DataSet.FieldCount - 1 do

      begin

       if DataSet.Fields[i].IsNull then

        exit;

       if DataSet.Fields[i].DataType in [ftString
    ftFixedChar ftGuid

        ftWideString] then

        if DataSet.Fields[i].AsString = '' then

         DataSet.Fields[i].Clear;

      end;

    end;



  • 相关阅读:
    1052 Linked List Sorting (25 分)
    1051 Pop Sequence (25 分)
    1050 String Subtraction (20 分)
    1049 Counting Ones (30 分)
    1048 Find Coins (25 分)
    1047 Student List for Course (25 分)
    1046 Shortest Distance (20 分)
    1045 Favorite Color Stripe (30 分)
    1044 Shopping in Mars (25 分)
    1055 The World's Richest (25 分)
  • 原文地址:https://www.cnblogs.com/carcode/p/1387855.html
Copyright © 2011-2022 走看看