2014-12-13 43 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