使用實體框架更新主鍵值

.net entity-framework sql-server vb.net

我正在嘗試從實體框架中更新復合主鍵的一個值,並且我收到此錯誤:“屬性'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()

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


熱門答案

我有博士學位在cs中 - 在數據庫領域,所以這個答案將與程序員的觀點略有不同。儘管對Oliver Hanappi有所了解,如果密鑰不是代理密鑰,密鑰可以偶爾改變。例如自然鍵或複合鍵。例如。可以在美國更改您的SSN。但是,許多程序員多年來都會認為這是一個不可更改的密鑰,並將其用作原樣。更改由外鍵組成的複合主鍵更為常見。

我正在處理一個有三元關係的數據庫。特別是三個實體(外鍵是各自表中的代理主鍵)。但是,要在更改第三個實體時保留兩個實體之間的關係, 需要更改交集表的一部分(在MSDN上也稱為純連接表)主鍵。這是一個有效的設計,只能通過刪除三元關係交集表並將其替換為兩個二進制關係表(可能有自己的代理鍵)來改進。 EF會處理這個問題。此設計更改將使(多個 - >多個) - >多個或Parent1-Parent2 - >子孫模型(如果不清楚,請閱讀下面的示例)。實體框架可以正常工作,因為每個關係實際上是一對多的關係。但從DB的角度來看,這是一個瘋狂的設計。讓我舉個例子說明原因。

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

類( SurrogateKeyClassInstructorIDCourseID

ClassRoomUsed( SurrogateKeyClassroomUsedSurrogateKeyClassClassRoomID

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

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

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

免費的另一個例子:

考慮學生,課程,年級協會。學生通過成績與課程相關聯。通常這是Student和一個Course之間的多對多關聯,在關聯表中有一個名為grade的附加字段(關聯表有有效載荷數據,如等級,交集表沒有有效載荷,在MSDN中稱為純連接表,在一個地方租賃):

學生( StudentID ,....)

課程( CourseID ,...)

考試StudentIDCourseID ,年級)

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

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

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

發生了引用完整性約束衝突:當依賴對象為Unchanged時,除非將其設置為關聯的主體對象,否則無法更改作為參照完整性約束一部分的主鍵屬性。必須跟踪主要對象,並且不標記為刪除。

屬性“X”是對象的關鍵信息的一部分,無法修改。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow