2014-02-14 65 views
0

我很難搞清楚如何更新我的實體及其相關數據。使用惰性加載..更新複雜的模型綁定EF5 ASP.NET MVC4

我有以下實體模型

public class Config 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public Int32 Id { get; set; } 

    [Required] 
    [MaxLength(100)] 
    public String Name { get; set; } 

    public virtual IList<DataField> DataFields { get; set; } 
} 

public class DataField 
{ 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public Int32 Id { get; set; } 

    [ForeignKey("Config")] 
    public Int32 ConfigId { get; set; } 

    public virtual Config Config { get; set; } 

    [Required, MaxLength(1000)] 
    public String Name { get; set; } 
} 

與相應的視圖模型。我已將它們刪除,刪除驗證等。

public class ConfigViewModel 
{ 
    public Int32 Id { get; set; } 

    public String Name { get; set; } 

    public IList<DataFieldViewModel> DataFields { get; set; } 

    public ConfigModel() 
    { 
     DataFields = new List<DataFieldViewModel>(); 
    } 
} 
public class DataFieldViewModel 
{ 
    [Required] 
    public Int32 Id { get; set; } 

    public String Name { get; set; } 
} 

在我Edit.cshtml形式我動態地添加新的數據域,當我發帖的形式,他們得到適當的deserialised到ConfigViewModel.DataFields。只要一切正常, 但是,我如何轉換這些模型,並更新實體模型? 如果我發佈新的數據字段,他們的ID將爲0,他們應該被添加,但已經有一個ID,應該更新.. 我不知道如何做到這一點,並且找不到任何東西相關的,或者我能理解的。

我在ConfigController中有以下內容。

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Edit(ConfigViewModel model) 
{ 
    try 
    {  
     if (!ModelState.IsValid) 
      return View(); 

     var config = uow.Repository<Entity.Models.Config>().FindById(model.Id); 

     config.Name = model.Name; 

     // Do something with the datafields 
     // config.DataFields 

     uow.Repository<Entity.Models.Config>().Edit(config); 
     uow.Save(); 

     return RedirectToAction("Index"); 
    } 
    catch(Exception ex) 
    { 
     ModelState.AddModelError("Error", ex.Message); 
     return View(model); 
    } 
} 

在我的倉庫,我有:

public void Edit(TEntity entity) 
{ 
    var entry = Context.Entry<TEntity>(entity); 
    entry.State = EntityState.Modified; 
} 

我Edit.cshtml形式看起來像

@for(var i = 0; i < Model.DataFields.Count; i++) 
{ 
    <tr>       
     <td>@Html.HiddenFor(m => m.DataFields[i].Id)</td> 
     <td>@Html.TextBoxFor(m => m.DataFields[i].Name)</td> 
     <td>@Html.EnumDropDownListFor(m => m.DataFields[i].Type)</td> 
    </tr> 
} 

回答

0

它看起來像一對夫婦的事情發生在這裏。

如果我正確理解您的數據結構,則表示有一個Config對象,該對象具有零個或多個與之關聯的對象DataField

應用程序的編輯頁面編輯Config對象允許您添加DataField項目修改現有DataField項目。

我假設在你的榜樣的註釋部分:

// Do Something with the DataFields 
// config.DataFields 

,你翻譯的視圖模型回你的域對象。

現在我假設你使用的是每個請求的生命週期爲DbContext,因爲這是最典型的在這些情況下。因此,在每個Web請求中,新的DbContext被實例化爲MVC控制器及其依賴項(例如服務,存儲庫,工作單元等)的實例化鏈的一部分。因此,在編輯Config對象的新請求中,DbContext爲空—由於它是全新的DbContext,因此它不知道任何對象。

此時,您需要AttachConfig實體到DbContext,以便DbContext將開始跟蹤它。如果有關於Config實體的任何更改(例如名稱已更改,或者已將新的DataField對象添加到集合中?),您需要將DbContext中的實體狀態設置爲Modified(您在上面的示例中完成了這一操作)。

裝上Config實體向DbContext也將導致所有被編輯過的Config實體引用的相關DataField對象連接。但有一點點皺紋。您需要告訴DbContext哪些實體是新的,哪些是修改的。您可以很容易地從修改的實體中知道新實體,因爲DataField.Id屬性將爲0.但是,您如何判斷現有的DataField實體是否已經原樣返回?這很重要,因爲只需將DataField實體附加到DbContext就可以在上下文中將它們置於Unmodified狀態。因此,如果現有實體發生任何更改,那麼在提交上下文時這些更改將不會持久。

解決此問題的一種天真的方法需要將所有DataField實體的Id屬性非零與Modified狀態設置爲非零。這會增加數據庫的負載(但對於小應用程序來說,這可以忽略不計)。但是,如果您在創建或更新記錄時有任何觸發器或其他審計機制,這不是一個好的解決方案。假設你不執行審計,天真的方法可能會工作得很好:

public void Edit(TEntity config) 
{ 
    Context.Attach<TEntity>(config); 
    Context.Entry<TEntity>(config).State = EntityState.Modified; 

    foreach(var df in config.DataFields) 
    { 
     Context.Entry<DataField>(df).State = EntityState.Modified; 
    } 

    // I noticed you never saved the changes to the DbContext. Do you need 
    // to do this here, or are you doing it with your UOW somewhere else?? 
    Context.SaveChanges(); 
} 

再次,這是一個幼稚的做法,一般應爲小型應用工作。至少,它應該讓您更好地瞭解在斷開連接的N層場景中使用Entity Framework時需要注意的事情。

另外,我強烈建議你看看下面的書:

的那些書每個討論你在談論的場景。由於您首先使用代碼,因此您可能希望從Code First書開始。

HTH