解決Delphi ADO無法爲更新定位行。一些值可能已在最後一次讀取後已更改的問題

解決Delphi ADO無法爲更新定位行。一些值可能已在最後一次讀取後已更改的問題  

2012-11-21 20:39:31|  分類: 數據庫相關 |  標籤:sql  delphi  數據庫  |舉報|字號 訂閱

解法一:

Delphi中很多朋友使用ADOQuery更新數據時會出現,無法爲更新定位行。一些值可能已在最後一次讀取後已更改的錯誤信息。

以前的時候也碰到類似的問題,一般就是去看數據表,發現沒有設置主鍵或者表裏的字段有的沒有默認值什麼的。說來也怪,設置上主鍵或者默認值都基本搞 定。也就沒有仔細研究錯誤的原因。但是今天又碰到類似的問題,還是照以前的解決辦法去設置,結果無語了,怎麼搞都解決不了問題,在網上查找了相關資料得到 如下解決方法:

在TADOQuery打開後加入TADOQuery(DataSet).Properties.Get_Item(‘Update Criteria’).Value :=0 語句。

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

就是將“TADOQuery(DataSet).Properties.Get_Item(‘Update Criteria’).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  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中有三種狀態 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事件中添加代碼,代碼如下:  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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章