解决Delphi ADO无法为更新定位行

解决Delphi ADO无法为更新定位行。一些值可能已在最后一次读取后已更改的问题



解法一:

Delphi中很多朋友使用ADOQuery更新数据时会出现,无法为更新定位行。一些值可能已在最后一次读取后已更改的错误信息。

以前的时候也碰到类似的问题,一般就是去看数据表,发现没有设置主键或者表里的字段有的没有默认值什么的。说来也怪,设置上主键或者默认值都基本搞定。也就没有仔细研究错误的原因。但是今天又碰到类似的问题,还是照以前的解决办法去设置,结果无语了,怎么搞都解决不了问题,在网上查找了相关资料得到如下解决方法:

在TADOQuery打开后加入TADOQuery(DataSet).Properties.Get_Item(‘UpdateCriteria’).Value :=0 语句。

示列:
procedure TfrmMain.aqryPubAfterOpen(DataSet: TDataSet);
begin
TADOQuery(DataSet).Properties.Get_Item(‘Update Criteria’).Value :=0;
end;

就是将“TADOQuery(DataSet).Properties.Get_Item(‘UpdateCriteria’).Value := 0;”加到你的要保存的ADOQuery控件的“AfterOpen”事件里面,应该是适用于所有的ADOQuery的。

TADOQuery(DataSet).Properties[]就为设置ADO地选项.

Update Criteria为自动生成SQL语句时WHERE语句地生成方式,取值如下:
adCriteriaKey = 0: 仅使用主键
adCriteriaAllCols = 1: 使用所有字段
adCriteriaUpdCols = 2: 仅使用修改地字段(默认值)
adCriteriaTimeStamp = 3: 使用时间戳字段(假如有地话)

原文地址:http://www.radxe.com/?p=527| 易胜领地-Delphi编程

 

解法二:
ADOQuery->Post更新问题: 无法为更新定位行。一些值已在最后一次读取后已更改...
原因:表中的数据和需要更新的数据一致,无须修改,当使用mysql时需要判断(mssql不需要)
错误写法:
  ADOQuery1->Edit();
       ADOQuery1Score->Value = 100;
        ADOQuery1->Post();
       ADOQuery1->Close();
正确写法:

  ADOQuery1->Edit();
        if( ADOQuery1Score->Value!=100) //先判断是否相等,再修改
       ADOQuery1Score->Value = 100;
        ADOQuery1->Post();
       ADOQuery1->Close();
解法三:

在Delphi中,如果使用ADOQuery插入数据没有问题, 之后对数据进行修改保存时,就会遇到“无法为更新定位行,一些值可能已在最后一次读取后已更改”的问题。

  原因有这样几种:

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

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

 解决方法:

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

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

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

 

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

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

  分析错误出现的情况

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

2.对一条数据中文本字段进行第二次修改时提示同样错误。  分析:第一次修改不报错,第二次就报错,两次都是执行UPDATE,区别可能就是,第一次和第二次的一些状态不同了。   跟踪ORACLE,得到执行错误时的脚本

 UPDATE "测试" SET "档号"=:V00001

 WHERE "档号"=:V00002 AND  "ROWID"=:V00003

 value="eee" value="AAAD7CAAGAAACgPAAI" 

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

UPDATE "测试" SET "档号"=:V00001

 WHERE "档号" IS NULLAND"ROWID"=:V00002

value="eee" 

value="AAAD7CAAGAAACgPAAI"  

 根据以上跟踪的结果,找到了问题的所在,"档号"=’’ 和 "档号" IS NULL 在ORACLE是不同的, "档号"=’’在ORACLE 不能定位到正确的记录行,所以造成了更新的失败。  我们知道ORACLE中文本型字段有两种状态NULL 和NOT NULL,而MSSQL中有三种状态 NULL,NOT NULL 和’’ ,这就是为何以上程序在MSSQL中运行正常,而在ORACLE中却不能正常的原因了。(注:Oracle中如设置一个文本字段=’’,Oracle会自动将其转换为NULL,但是在查询时如果这样用就不行,不知能不能算是ORACLE的一个BUG。)  为何在第一次编辑时能正确生成代码,而在第二次就不可以了。原因就是Delphi中的TField的属性IsNULL,第一次其从数据库中取出了正确的状态为IsNull=True,编辑之后,如果数值=’’,其IsNull就是False,而TAdoQuery生成更新脚本时就是根据这个属性来生成=’’和 IS NULL这两种脚本的。  找到问题,我们就可以写代码来解决问题了。分析以上问题,我们只要在使用ORACLE数据库时,在提交前,将文本字段=’’字段的IsNull=True,就可以了,我们在TADOQuery的BeforePost事件中添加代码,

代码如下:

procedureTFrmData.adoqMainBeforePost(DataSet: TDataSet);
var
  i:Integer;
begin
 ifDATA = 'ORACLE' then //自定义,标明数据库类型
 fori := 0 toDataSet.FieldCount - 1 do
 begin
   ifDataSet.Fields[i].IsNullthen exit;
  ifDataSet.Fields[i].DataType in [ftString, ftFixedChar, ftGuid, ftWideString] then
   ifDataSet.Fields[i].AsString = '' then
       DataSet.Fields[i].Clear;
 end;
end;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值