2014-12-13 39 views
2

...我已經尋找這個話題,我意識到有一個輕微的相關問題here,雖然這個問題聽起來很相似,接受的解決方案沒有工作(其中,如果讀取評論,人們會知道問題沒有真正解決)。更新實體,所有的變化不節能

這裏是我的問題,我希望有人能夠幫助:

我有一個實體:

public class Garden 
{ 
    public virtual int Id { get; set; } 
    public virtual string Name { get; set; } 
    public virtual PlantHardinessZone Zone { get; set; } 
} 

它有PlantHardinessZone實體的關係:

public class PlantHardinessZone 
{ 
    public int Id { get; set; } 
    public string Zone { get; set; } 
} 

爲了容易使用區域的DropDownListFor,我創建了一個視圖模型:

public class GardenViewModel 
{ 
    public int ZoneId { get; set; } 
    public IEnumerable<PlantHardinessZone> Zones { get; set; } 

    public Garden Garden { get; set; } 
} 

此ViewModel用於多個視圖。它目前按照預期創建一個新的Garden實體,但是,編輯不能正常工作。如果我更改區域,它不會在數據庫中更新。我瀏覽了代碼,並從視圖返回正確的區域信息,它只是不更新​​。如果我更改花園的名稱,那更新不錯。

這裏是[HttpPost}編輯操作:

[HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult Edit(GardenViewModel viewModel) 
    { 
     if (ModelState.IsValid) 
     { 
      Garden garden = viewModel.Garden; 
      garden.Zone = db.Zones.Where(z => z.Id == viewModel.ZoneId).Single(); 
      db.Gardens.Attach(garden); // per the solution accepted [here][2] 
      db.Entry(garden).State = EntityState.Modified; 
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 
     return View(viewModel); 
    } 

這裏是相應的視圖:

@model GardenManager.Web.ViewModels.GardenViewModel 

@{ 
    ViewBag.Title = "Edit"; 
} 

<h2>Edit</h2> 


@using (Html.BeginForm()) 
{ 
    @Html.AntiForgeryToken() 

    <div class="form-horizontal"> 
     <h4>Garden</h4> 
     <hr /> 
     @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
     @Html.HiddenFor(model => model.Garden.Id) 

     <div class="form-group"> 
      @Html.LabelFor(model => model.Garden.Name, htmlAttributes: new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.Garden.Name, new { htmlAttributes = new { @class = "form-control" } }) 
       @Html.ValidationMessageFor(model => model.Garden.Name, "", new { @class = "text-danger" }) 
      </div> 
     </div> 
     <div class="form-group"> 
      <div class="col-md-10 col-md-offset-2"> 
       @Html.DropDownListFor(model => model.ZoneId, 
       new SelectList(Model.Zones, "Id", "Zone", Model.ZoneId), 
       "Select Zone", new { @class = "form-control" }) 
      </div> 
     </div> 

     <div class="form-group"> 
      <div class="col-md-offset-2 col-md-10"> 
       <input type="submit" value="Save" class="btn btn-default" /> 
      </div> 
     </div> 
    </div> 
} 

<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 

@section Scripts { 
    @Scripts.Render("~/bundles/jqueryval") 
} 

誰能幫我直接解決這個非常惱人的問題?歡迎和欣賞所有的輸入。非常感謝!

+0

'db。條目(花園).State = EntityState.Modified'只將「花園」標記爲已修改,而不是其導航屬性。這就是你的困惑。在斷開連接的環境中使用EF並不像應該那樣容易。您必須遍歷整個對象圖,才能將所有修改都更改爲更改跟蹤器。有一個圖書館,[Graphdiff](https://github.com/refactorthis/GraphDiff)可以爲你完成這項任務。 – 2014-12-13 20:17:53

+0

我的困惑來了,因爲在我的腦海中,區域正在改變,只是花園中的FK指向了適當的區域。根據答案,我添加了一個明確的FK(ZoneId),並按照我的預期進行更新。 :) – OCDDev 2014-12-13 22:28:56

回答

0

你花園設置狀態Modified但是,這並不對導航性能(鏈接)任何影響。因此EF將只更新花園,對鏈接區沒有影響。

但是,如果您分配通過它的ID,以garden.ZoneId,將工作。 garden.ZoneId花園的直接財產,它會得到一切正確的鏈接。

garden.ZoneId = db.Zones.Where(z => z.Id == viewModel.ZoneId).Single().Id; 

概括地說:
- garden.Zone不是對象的真實屬性,它只是由EF在後臺處理的鏈接。這就是更新失敗的原因。
- garden.ZoneId是對象的真實屬性,從而得到,如果你改變它的正確更新。

db.Gardens.Attach(garden);高度只有garden對象。它不附加可能與之鏈接的其他對象。

此外,我會推薦給實體首先重視的背景下,然後改變它的性質和狀態。

+0

但是,我看到你在說什麼,** Zone **實際上並沒有改變,只是識別哪個** Zone **的FK,但仍然保存在** Garden **內,除非我是遺漏了什麼。我試過'db.Entry(garden.Zone).State = EntityState.Modified;',但是提示錯誤在'db.Entry(garden.Zone).State = EntityState.Added;' 運行:「存儲更新,插入或刪除語句會影響意外數量的行(0)。自實體加載後,實體可能已被修改或刪除。刷新ObjectStateManager條目。「我試圖糾正,但是,沒有運氣。 – OCDDev 2014-12-13 22:11:37

+0

你有沒有試過我的第二個建議? – 2014-12-13 22:13:27

+0

我有,是的。我不得不爲** ZoneId **和遷移添加一個顯式屬性,這是我做的。它的工作,所以非常感謝你。我不確定爲什麼會產生這樣的差異,但我仍然在學習。 :) 再次感謝你。 – OCDDev 2014-12-13 22:26:13