更新实体,所有更改都不保存

时间:2014-12-13 18:45:00

标签: c# asp.net-mvc entity-framework c#-4.0 razor

我已经搜索了这个主题,并且我发现有一个稍微相关的问题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中轻松使用区域,我创建了一个ViewModel:

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

    public Garden Garden { get; set; }
}

此ViewModel用于多个视图。它目前可用于创建新的Garden实体,但是,编辑功能不正常。如果我更改了区域,则不会在数据库中更新。我已经完成了代码,并且正在从View返回正确的区域信息,它只是没有更新。如果我更改花园的名称,那就更新了。

这是[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")
}

任何人都可以帮我指导解决这个非常恼人的问题吗?所有输入欢迎和赞赏。非常感谢你!

1 个答案:

答案 0 :(得分:0)

您正在将 Garden 的状态设置为Modified,但这对导航属性(指向区域的链接)没有任何影响。因此,EF只会更新花园,而不会影响关联的区域

但是,如果您将区域指定为ID,请garden.ZoneId,这将有效。 garden.ZoneId Garden 的直接属性,它会将所有内容正确链接。

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

总结一下:
  - garden.Zone 不是对象的真实属性,它只是EF幕​​后处理的链接。这就是更新失败的原因 - garden.ZoneId 是对象的真实属性,因此如果您更改它,它会得到正确更新。

db.Gardens.Attach(garden);仅附加garden个对象。它不会附加可能与其链接的其他对象。

此外,我建议首先将实体附加到上下文,然后更改它的属性和状态。