2013-04-09 64 views
1

當我嘗試新的子關係添加到現有的父對象的新子插入,實體試圖插入父對象爲,而不是更新它修改。我得到一個錯誤,說它試圖插入一個重複密鑰現有父實體框架4

這真的讓我感到困惑,直到我用新的關係更新模型(通過數據庫更新而不是代碼優先)之後,它才表現得像這樣。其他表在相同的情況下,具有相同的多對多模式不會導致此錯誤!

我發現,如果我將我的子對象添加到上下文中,請仔細設置ID值而不是導航屬性,它將保存正常。 但是修復過程不會將子對象添加到導航集合,這會導致其他位置出現邏輯問題。

我的模型有一個多對多的關係是這樣的:

選項 - < optionUnit> - 單位

兩個選項和單元對象現有加載到上下文。

通常我會做網橋表,並設置像下面的導航屬性:

bridge = new OptionUnit() 
{ 
    OptionUnitId = Guid.NewGuid(), 
    Unit = SelectedUnit, 
    Option = SelectedOption, 
}; 
//Context.OptionUnits.Add(bridge); //added to context via the navigation properties 

但是,當我這樣做的時候,實體試圖插入SelectedOption新的(即使它的實體狀態在時間體改的保存,不是新的或分離的)。

爲了解決這個問題,我不得不做橋,並設置ID的唯一。我在保存時沒有錯誤,但它不會像我所期望的那樣通過修復自動添加到SelectedOption.OptionUnits中。如果我手動將它添加到集合中,則會再次出現保存錯誤。

bridge = new OptionUnit() 
{ 
    OptionUnitId = Guid.NewGuid(), 
    //Unit = SelectedUnit, 
    UnitId = SelectedUnit.UnitId, 
    //Option = SelectedOption, 
    OptionId = SelectedOption.OptionId, 
}; 
Context.OptionUnits.Add(bridge); 

這似乎只發生在關於Options Entity的關係上。 optionUnit> - Unit之間的另一個關係沒有問題,並按預期工作。

看起來好像他們的關係錯了,但我不確定在哪裏看。 我需要知道什麼導致這種行爲,如何解決它,以及如何防止它在未來發生......

回答

0

我發現了這個問題。添加子項後,我會運行一些邏輯來更新一些總數。問題是我用RaiseDataMemberChanged(「sum」)而不是RaisePropertyChanged(「sum」)。 RaiseDataMemberChanged()必須將實體中的某些內容標記爲修改過的內容,這是造成這個問題的原因。 感謝IronMan84的幫助。

3

令人難以置信的是,朱莉Lerman只是有一個驚人的MSDN文章關於這個確切的問題,爲什麼它發生。你可以找到文章right here

在朱莉自己的話說:

它發生的原因是,當您使用DbSet.Add方法,不僅是根實體的狀態標記爲「增加」,但一切都在圖表中該上下文之前並不知道被標記爲已添加。儘管開發人員可能知道該對象具有現有的Id值,但實體框架將授予其EntityState(已添加)併爲該對象創建一個Insert數據庫命令,而不管現有Id如何。

所以這裏簡要介紹的是,當你說Context.OptionUnits.Add(bridge);時,它也認爲你正試圖爲它添加Option和Unit對象。相反,你需要使用FK(如她所提到的)然後添加它。

我認爲這就是你在第二次嘗試時所要做的,但我想知道你是如何檢查它是否在SelectedOption.OptionUnits。試圖在保存後檢查它嗎?在這種情況下,它不會顯示出來,因爲該值在被Entity Framework拉出時被緩存在內存中。之後您需要嘗試再次提出該對象。

+0

感謝您的文章!我現在正在閱讀它,它似乎確認它應該如何工作,因爲我不是處於斷開連接狀態時的工作方式 「當您在客戶端應用程序中工作時,或者在單個單元中執行這些步驟時在上下文跟蹤所有活動的情況下工作,這是您可能期望的行爲,但是,如果您使用斷開連接的數據,則行爲會非常不同,這讓很多開發人員感到驚訝。 – Shaboboo 2013-04-10 15:48:03

+0

將新對象添加到上下文之後,我期望「修復」過程應該通過並將相關實體連接在一起。然後該選項應該在OptionUnit的導航集合中包含OptionUnit。我希望在保存之前發生這種情況,就像我在應用程序中的其他地方一樣。 我在將它添加到上下文後使用ExistingOption.UnitOptions.Contains(newUnitOption)對其進行檢查。 – Shaboboo 2013-04-10 15:53:25

+0

只需將它添加到上下文中就行不通,因爲在調用SaveChanges之前,您尚未保存它。 – IronMan84 2013-04-10 15:56:14