Dot-Net

使用實體框架更新主鍵值

  • September 2, 2009

我正在嘗試從實體框架內更新復合主鍵的一個值,但出現此錯誤:“屬性‘CustomerID’是對象的關鍵資訊的一部分,無法修改。”

這是我的程式碼:

Dim customer As Customer = (From c In db.Customer Where c.CustomerID = "xxx" AndAlso c.SiteKey = siteKey).FirstOrDefault
customer.CustomerID = "fasdfasdf"
db.SaveChanges()

似乎太簡單了。您不能在實體框架中更新主鍵,這是真的嗎?我找不到有關該主題的任何文件。謝謝!

你不能,而且有充分的理由。見 KM 評論。

我說你可以做的一件事是有兩張表,一張是匿名數據,一張是在他們登錄後儲存真實使用者數據。

或者你可以(我沒有測試或做過)有這種表格佈局:

---Customers----
AutoNumber PK <- This links to all other tables in your database, and does NOT change.
CustomerID  <- This can change.
CustomerType <- Anonymous or logged in.  

當他們登錄時,您將 CustomerType 和 CustomerID 更改為您需要的。

因此,您的查詢可能如下所示:

Dim customer As Customer = (From c In db.Customer _
                           Where c.CustomerID = {Some temp ID} _
                           AndAlso c. CustomerType = "Anonymous").FirstOrDefault
// After user logs in.
customer.CustomerID = {Make a new user ID here}
customer.CustomerType = "LoggedIn" {or what ever}
db.SaveChanges()

請注意,自動編號主鍵永遠不會改變。這樣一來,您與客戶表有關係的任何表仍然可以工作,並且不必對主鍵進行級聯更新*(這就像用鉛筆刺傷自己的眼睛)。*

我有博士學位。在cs - 在數據庫領域,所以這個答案將與程序員的觀點有所不同。就 Oliver Hanappi 而言,如果一個鍵不是代理鍵,它可以並且偶爾會發生變化。例如自然鍵或複合鍵。例如。在美國可以更改您的 SSN。但是多年來,許多程序員會認為這是一個不可更改的密鑰並就這樣使用它。更改由外鍵組成的複合主鍵更為常見。

我正在處理具有三元關係的數據庫。特別是三個實體(外鍵是各自表中的代理主鍵)。但是,為了在更改第三個實體的同時保留兩個實體之間的關係,需要更改部分交集表(在 MSDN 上也稱為純連接表)主鍵。這是一個有效的設計,只能通過刪除三元關係交集表並將其替換為兩個二元關係表(可能有自己的代理鍵)來改進。EF 會處理得很好。此設計更改將生成 (Many->many)->many 或 Parent1-Parent2 -> Child-grandchild 模型(如果不清楚,請閱讀下面的範例)。實體框架可以很好地解決這個問題,因為每個關係實際上都是一對多的關係。但從數據庫的角度來看,這是一個瘋狂的設計。讓我舉個例子告訴你為什麼。

考慮到課程、教室和講師在班級中相互關聯。類可以包括:CourseID、ClassroomID、InstructorID 作為外鍵,並包含一個包含所有三個的複合主鍵。雖然是一個清晰、簡潔的三元模型(3 向關係),但我們可以將其分解為二元關係。這將給出兩個交集表。添加代理鍵將滿足 EF 如下:

類(SurrogateKeyClassInstructorIDCourseID

ClassRoomUsed(SurrogateKeyClassroomUsedSurrogateKeyClassClassRoomID

這種設計的問題是我們可以多次關聯相同的課程和講師,這是以前的模型避免的。為避免此問題,您可以在數據庫中添加兩個 ID 欄位的唯一性約束,但是當您只處理代理鍵時為什麼要這樣做呢?然而,這個解決方案將盡我所能。然而,這不是邏輯數據庫設計,因為數據庫中需要非自然的唯一約束。

但是,如果您不想更改數據庫或無法更改數據庫,這裡是第二種解決方案:交叉/關聯表就是這樣,將兩個或多個實體連結在一起的連結。如果其中一個發生更改,請刪除關聯並重新創建一個具有適當外鍵(導航屬性)的新關聯。這意味著您將不允許在任何關係中要求子實體,但這是非常常見的。

我建議實體框架(將來)允許我們這些可以設計優雅的數據庫模型的人在需要時更改交集/關聯表中的部分鍵!

另一個免費範例:

考慮一個學生、課程、年級關聯。學生通過成績與課程相關聯。通常這是 Student 和 Course 之間的多對多關聯,關聯表中有一個稱為 Grade 的附加欄位(關聯表具有像等級這樣的有效負載數據,交叉表沒有有效負載,並且在 MSDN 中稱為純連接表租在一處):

學生(學生ID,….)

課程(課程ID,…)

服用(學生ID,課程ID,成績)

如果有人從下拉列表中輸入數據錯誤並將學生放在錯誤的班級,您希望他們稍後通過再次選擇下拉列表並選擇不同的課程來更改它。在後台,您需要從 Take 表中刪除 EF 對象並重新創建它,而不會失去分數(如果有的話)。簡單地更改外鍵CourseID似乎是一個更好的選擇。如果這個看起來很做作,請提出你自己的聯想,但作為一名教授,這對我來說很自然。

結論:當您有一系列關係時,最好不要允許級聯和/或更改 FK,但存在需要它的合理/邏輯場景,即使通常不推薦作為最佳實踐。

此問題可能會出現以下異常,具體取決於您是分別更改模型中的導航屬性還是鍵屬性:

發生參照完整性約束衝突:當從屬對象未更改時,作為參照完整性約束一部分的主鍵屬性不能更改,除非它被設置為關聯的主體對象。必須跟踪主體對象並且不標記為刪除。

屬性“X”是對象的關鍵資訊的一部分,不能修改。

引用自:https://stackoverflow.com/questions/1367751