摘要:LINQ to SQL–更新多主鍵資料表的主鍵值
今天要用 LINQ to SQL (Oracle) 更新某欄位值時,發現無法更新成功,但是沒有錯誤訊息。範例資料和更新的 LINQ 語法如下:(LINQPad 版本)
執行沒有錯誤,但是序號 3 的 ID 欄位值並沒有修改為「X」,仍保留原有的「C」,所以就檢查一下 LINQ to SQL 所產生的 SQL Script:
SELECT * FROM (SELECT t0.ID, t0.NAME, t0.SN
FROM FOO t0
WHERE (t0.SN = 3)) WHERE ROWNUM<=1
UPDATE FOO
SET NAME = :p1
WHERE ((ID = :p0) AND (SN = 3))
-- p0 = [X]
-- p1 = [PINK]
SELECT t0.ID, t0.NAME, t0.SN
FROM FOO t0
WHERE (t0.SN = 3)
發現上面 Update 語法中,把 ID 欄位放到 Where 條件裡,而條件值是我在 LINQ 中更新的「X」,所以執行時不會發生錯誤,只是更新 0 筆。看到這個狀況後,猜想原因應該是資料表為多主鍵結構,而我要更新的欄位是主鍵之一,所以到 DB 中查一下:
CREATE TABLE FOO
(
sn NUMBER NOT NULL,
ID VARCHAR2(20) NOT NULL,
NAME VARCHAR2(200)
);
COMMENT ON TABLE FOO
IS 'LEO測試資料表';
COMMENT ON COLUMN FOO.sn
IS '流水號';
COMMENT ON COLUMN FOO.id
IS '證號';
COMMENT ON COLUMN FOO.name
IS '姓名';
ALTER TABLE FOO
ADD CONSTRAINT PK_FOO PRIMARY KEY (SN, ID)
USING INDEX ;
果不其然,SN 和 ID 是複合主鍵。但是更新 ID 的需求仍然存在,該怎麼辦?『理想世界』的解法是:
- 移除原本的雙主鍵結構。
- 設定 SN 欄位為 Primary key。
- 設定 SN + ID 為 Unique index。
類似的方法還有加一個新的欄位當主鍵之類的方式,但這都是理想世界的解法啊!一個運行多年的龐大系統,要異動資料表的結構可是要經過重重關卡審核,還要附保證書(保證系統中其他上百個功能不會因此發生問題),只為了能夠透過 LINQ to SQL 修改其中一個主鍵值?CP 值太低了。所以乾脆改用一刪一加的方式處理:
上述語法會轉換為以下的 SQL:
SELECT t0.ID, t0.NAME, t0.SN
FROM FOO t0
WHERE (t0.SN = 3)
SELECT * FROM (SELECT t0.ID, t0.NAME, t0.SN
FROM FOO t0
WHERE (t0.SN = 3)) WHERE ROWNUM<=1
DELETE FROM FOO
WHERE ((ID = :p0) AND (SN = 3))
-- p0 = [C]
INSERT INTO FOO(ID, NAME, SN)
VALUES (:p0, :p1, 3)
-- p0 = [X]
-- p1 = [PINK]
SELECT t0.ID, t0.NAME, t0.SN
FROM FOO t0
WHERE (t0.SN = 3)
先刪後加的原因是,避免重複執行時發生主鍵重複的錯誤,不過上述做法一定要確保他們是在【同一個交易中】執行,不然資料刪完,新增不回去,事情就大條了!!!
--------
沒什麼特別的~
不過是一些筆記而已