關聯式資料庫裡有個很基本的特性: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】,至少心裡也有方向,不會再這麼害怕去打老虎了。如果未來有抓到老虎,會陸續更新在這一篇文章中。
沒有留言:
張貼留言