資料庫編程中,確保關鍵欄位 (如員工編號、身分證號) 唯一性是基本需求。本文示範在 TTable.BeforePost 事件中,建立第二個 TTable 實例以 FindKey 快速查詢,若鍵值已存在則 Abort 取消寫入並彈出警告,保證資料完整性。
Renshi.dbf (dBASE/Paradox)Bianhao (編號,字串型),已建立索引DBEdit1 綁定 Bianhao,DBEdit2 綁定 Xingming
procedure TForm1.Table1BeforePost(DataSet: TDataSet);
var
CheckTable: TTable;
begin
CheckTable := TTable.Create(Self);
try
CheckTable.DatabaseName := 'C:\';
CheckTable.TableName := 'Renshi.dbf';
CheckTable.IndexFieldNames := 'Bianhao'; // 使用索引加速
CheckTable.Open;
CheckTable.SetKey;
CheckTable.FieldByName('Bianhao').AsString := DBEdit1.Text;
if CheckTable.GotoKey then // 找到重複鍵值
begin
ShowMessage('輸入的編號已存在!請重新輸入');
Abort; // 取消 Post,資料不寫入
end;
finally
CheckTable.Free;
end;
end;
DataSet 的游標狀態與編輯模式。GotoKey 走 B-tree 查找,極快 (O(log n))。GotoKey 回傳 True 表示找到。BeforePost 中呼叫 Abort 會拋出 EAbort 例外,VCL 捕獲後取消寫入並保持編輯狀態,使用者可修正後再存。| 方案 | 優點 | 缺點 |
|---|---|---|
| 資料庫層級 Primary Key / Unique Constraint | 最可靠、效能最好、跨應用共享 | 需資料庫支援 (Paradox/dBASE 支援有限) |
| TTable.BeforePost + FindKey (本文) | 無需資料庫結構變更、邏輯集中在應用層 | 高併發下可能有競態條件 (需鎖表/交易) |
| OnValidate 檢查 | 即時回饋 (離開欄位時) | 同樣有競態風險 |
| ClientDataSet + OnReconcileError | 離線模式友善 | 架構較複雜 |
// 在資料庫支援交易時 (如 InterBase, Firebird, SQL Server)
procedure TForm1.Table1BeforePost(DataSet: TDataSet);
begin
Database1.StartTransaction;
try
// ... FindKey 檢查 ...
// ... 正常 Post ...
Database1.Commit;
except
Database1.Rollback;
raise;
end;
end;
BeforePost + FindKey + Abort 是 Delphi BDE/ADO 傳統架構下防止重複鍵值的經典寫法。理解 SetKey/GotoKey 索引尋找機制、Abort 取消寫入語意、獨立 TTable 避免游標衝突,即可靈活應用於各類唯一性驗證場景。