2017/07/26

一山不容二虎之 EDBClient - Key violation 記事



關聯式資料庫裡有個很基本的特性:PRIMARY KEY 條件約束。




一個資料表只能有一個 PRIMARY KEY 條件約束,並且任何加入 PRIMARY KEY 條件約束的資料行都不可接受 Null 值。因為 PRIMARY KEY 條件約束保證唯一的資料,它們通常是定義在識別欄位上。

-- 摘自 TechNet : PRIMARY KEY 條件約束 章節

Delphi 的 TClientDataSet 也受到資料庫的約束,但為了可以在前端就可以檢查資料唯一性,避免和後端資料庫無謂的資料傳遞,【EDBClient : Key violation】,就是針對唯一性所帶出的例外訊息。

而我卻踩到了這個地雷,使用者反應在存檔的時候會跳出上面的錯誤視窗。

存檔的程式內容簡略如下:


if ClientDataSet1.Locate('PK1',[PK1Value],[]) then
  ClientDataSet1.Edit
else
begin
  ClientDataSet1.Append;
  ClientDataSet1.FieldByName('PK1').AsString := PK1Value
end
ClientDataSet1.FieldByName('PK2').AsString := PK2Value
ClientDataSet1.Field11.AsString := ...
.
.

看起來很正常,把 ClientDataSet1 另存 MyBase 搬到全新的專案上試試看能不能覆現。



答案是:【一切正常,無法覆現】!



但在原始專案卻會遇到【Key violation】的詭異情況。

在 Debug 的過程看到疑似可能的問題點:


  • ClientDataSet.State == dsEdit
  • PK2Value == ClientDataSet1.FieldByName('PK2').AsString


某一筆資料確實會發生:明明沒有重複資料,卻跳出 Key violation 例外的問題。

最終解法如下:


  • 限制 Primary Key Field 在前後值不相同時才可修改。
  • 只能在新增時寫入值到 Primary Key Field。


後記

雖然最終無法得知真實的原因,但如果遇到同樣的【Key violation】,至少心裡也有方向,不會再這麼害怕去打老虎了。

如果未來有抓到老虎,會陸續更新在這一篇文章中。

沒有留言:

張貼留言