2012-12-27 47 views
1

更新我的POCO的子對象與CodeFirst有問題。我的POCO的如下代碼優先不更新子對象

public class Place 
{ 
    public int ID { get; set; 
    public string Name { get; set; } 

    public virtual Address Address { get; set; } 
} 

public class Address 
{ 
    public int ID { get; set; 
    public string AddressLine { get; set; } 
    public string City { get; set; } 

    public virtual State State { get; set; } 
} 

public class State 
{ 
    public int ID { get; set; 
    public string Name { get; set; } 
} 

我有一個視圖來編輯地方及其孩子的所有領域。除了是DropDownList的狀態外,所有屬性都是文本框。

當用戶點擊保存按鈕時,視圖將返回所有已填充的Place屬性,但只填充了ID的狀態除外,因爲它的值來自DropDownList且Name爲空。

在編輯POST方法,我有以下代碼:從PlaceBLL類

if (ModelState.IsValid) 
{ 
    bool isNewPlace = place.ID == -1; 
    //Hack, State name is empty from View, we reload 
    place.Address.State = new StateBLL().GetByID(place.Address.State.ID); 
    new PlaceBLL().Update(place); 

    return RedirectToAction("Index"); 
} 

和更新代碼如下

protected override void Update(Place place) 
{ 
    MyDbContext.Instance().Set<Address>().Attach(place.Address); 
    MyDbContext.Instance().Entry(place.Address).State = System.Data.EntityState.Modified; 
    MyDbContext.Instance().Set<State>().Attach(place.Address.State); 
    MyDbContext.Instance().Entry(place.Address.State) = System.Data.EntityState.Modified; 
    MyDbContext.Instance().SaveChanges(); 
    } 

當用戶編輯將對象的所有字段都是正確更新,除了狀態,當用戶改變某個地方的狀態時,這個改變並不會持久到數據庫,如果看起來Code首先沒有檢測到用戶的狀態改變。

你知道爲什麼代碼首先不檢測一個地方的狀態改變值嗎?

謝謝。

+1

你的更新方法看起來很瘋狂。你有沒有充分的理由不使用基本的EF來做到這一點,即選擇 - >修改 - > saveChanges? –

回答

1

Update方法更新(標量屬性)Address並更新(標量屬性)State,但它不更新關係placeAddress之間(這不是一個問題,因爲你顯然只在您的視圖中編輯Address屬性,而不指定另一個Address實體到place),並且它不會更新place.Addressplace.Address.State之間的關係。但這是你在實際中改變的觀點。

要更新place.Addressplace.Address.State之間的關係你有兩種選擇:

  • 引進的外鍵屬性到您的Address類,它表示的FK的狀態(此類型的關聯被稱爲外鍵協會):

    public class Address 
    { 
        public int ID { get; set; 
        public string AddressLine { get; set; } 
        public string City { get; set; } 
    
        public int StateID { get; set; } 
        public virtual State State { get; set; } 
    } 
    

    然後確保你綁定您的下拉列表爲place.Address.StateID(而不是place.Address.State.ID)。將視圖發佈到服務器時,FK屬性​​將從下拉列表中填入新的選定ID。在你的Update方法中,你可以刪除第三和第四行。單獨更新Address也會更新​​外鍵。您也可以刪除編輯帖子操作中加載State的代碼。

  • 如果你想保留當前獨立協會(=關聯,而無需在模型類暴露的外鍵屬性),您必須從數據庫中加載的原始狀態,並用新狀態更新:

    protected override void Update(Place place) 
    { 
        var dbPlace = MyDbContext.Instance().Places.Include(p => p.Address.State) 
         .Single(p => p.ID == place.ID); 
    
        // Update scalar properties of place 
        MyDbContext.Instance().Entry(dbPlace) 
         .CurrentValues.SetValues(place); 
    
        // Update scalar properties of Address 
        MyDbContext.Instance().Entry(dbPlace.Address) 
         .CurrentValues.SetValues(place.Address); 
    
        // Change relationship between Adress and State 
        if (dbPlace.Address.State.ID != place.Address.State.ID) 
        { 
         MyDbContext.Instance().States.Attach(place.Address.State); 
         dbPlace.Address.State = place.Address.State; 
        } 
    
        MyDbContext.Instance().SaveChanges(); 
    } 
    

    同樣,你可以刪除代碼的加載State在編輯後您的操作,因爲正確的鍵屬性(State.ID)是足以改變的關係。

0

您還需要附加實體。以下是您需要做的簡單版本。

var updated = _dbSet.Attach(item); 
_dataContext.Entry(item).State = EntityState.Modified; 
return updated; 
+0

爲什麼有必要這樣做?如果我首先認真編寫代碼,那麼它會自動跟蹤所有更改?爲什麼有必要指定Place的一個子對象已更改? –

+0

@MarcCals因爲實體需要附加一個新增或修改的EF來產生一個查詢到數據庫。 –

+0

看你的代碼更好,這是我與MyDbContext.Instance做()設置().Attach(place.Address.State)相同。 MyDbContext.Instance()。Entry(place.Address.State)= System.Data.EntityState.Modified;這是真的嗎? –