我在Navigations
表的列中有一個唯一約束,名爲Index
。我有兩個Navigation
實體,我想交換他們的Index
值。在實體框架中使用唯一約束交換值
當我呼叫db.SaveChanges
時,它會拋出一個異常,指出違反了唯一約束。看來EF正在更新一個值,然後是另一個值,從而違反了約束條件。
它不應該在事務中更新它們,然後嘗試提交一次值,而不是違反約束?
有沒有辦法解決這個問題,而不使用臨時值?
我在Navigations
表的列中有一個唯一約束,名爲Index
。我有兩個Navigation
實體,我想交換他們的Index
值。在實體框架中使用唯一約束交換值
當我呼叫db.SaveChanges
時,它會拋出一個異常,指出違反了唯一約束。看來EF正在更新一個值,然後是另一個值,從而違反了約束條件。
它不應該在事務中更新它們,然後嘗試提交一次值,而不是違反約束?
有沒有辦法解決這個問題,而不使用臨時值?
這不是EF的問題,而是SQL數據庫的問題,因爲更新命令是按順序執行的。事務與此無關 - 所有約束都按每個命令而不是每個事務進行驗證。如果你想交換唯一的值,你需要更多的步驟,你將使用額外的虛擬值來避免這種情況。
這看起來很危險,因爲潛在的問題可能會出現使用相同虛擬值的併發請求,或者也可能是違反約束的虛擬值。您知道這種情況有沒有「最佳做法」? – 2012-04-19 11:07:40
您也可以刪除舊記錄並創建新記錄。我會盡力避免這一點。這是唯一約束不適合您的應用程序邏輯需求的情況。 – 2012-04-19 11:12:23
夠公平的。我只是要從數據庫中刪除唯一的約束。如果有重複,它不會造成任何問題。如果有的話,當他們顯示在導航欄上時,他們會處於不可靠的順序。 – 2012-04-19 11:26:52
您可以運行一個自定義的SQL查詢來交換值,如:
update Navigation
set valuecolumn =
case
when id=1 then 'value2'
when id=2 then 'value1'
end
where id in (1,2)
然而,實體框架不能這樣做,因爲它是一個ORM的範圍之內。它只是針對每個被更改的實體執行連續的update
陳述,就像他在答案中描述的拉迪斯拉夫一樣。
另一種可能性是放棄數據庫中的UNIQUE
約束,並依賴應用程序正確執行此約束。在這種情況下,EF可以保存更改,但取決於您的情況,這可能是不可能的。
有幾種方法。其中一些內容在其他答案和評論中有所涉及,但爲了完整起見,我將在這裏列出它們(請注意,這僅僅是我頭腦風暴的列表,可能並不完全)。
設置爲負值然後回到正值的想法很聰明,併爲我做了訣竅。謝謝! – jslatts 2016-07-14 02:21:08
你能展示一些代碼嗎? – Likurg 2012-04-19 10:58:53
這裏你需要臨時值,更新是一個自包含的操作。所以你總是會違反約束條件,唯一的辦法是禁用操作的約束條件。 – 2012-04-19 11:07:03