繁体   English   中英

更新复杂模型绑定EF5 ASP.NET MVC4

[英]Updating complex model binding 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表单中,我动态添加了新的数据字段,并且在发布表单时,已将它们正确反序列化为ConfigViewModel.DataFields。 这么久,一切正常。 但是,如何转换这些模型并更新实体模型? 如果我发布新的数据字段,则它们的ID将为0,应添加它们,但是应该更新已经具有ID的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>
}

似乎这里发生了几件事。

如果我正确理解您的数据结构,则您有一个Config对象,该对象具有零个或多个与其关联的DataField对象。

用于编辑Config对象的应用程序的“编辑”页面允许您添加新的 DataField项目 修改现有的 DataField项目。

我假设在您的示例的注释部分中:

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

您正在将视图模型转换回您的域对象。

现在,我假设您正在为DbContext使用每个请求的生存期,因为在这些情况下这是最典型的。 因此,在每个Web请求上,一个新的DbContext被实例化为MVC控制器及其依赖关系(例如服务,存储库,工作单元等)的实例化链的一部分。 因此,对于这个新的编辑Config对象的请求, DbContext为空-它不知道任何对象,因为它是一个全新的DbContext

此时,您需要Attach Config实体AttachDbContext以便DbContext开始对其进行跟踪。 如果对Config实体进行了任何更改(例如,名称是否更改,或者是否向集合中添加了新的DataField对象?),则需要将DbContext中的实体状态设置为Modified (在上面的示例中已完成此操作) )。

Config实体附加到DbContext还将导致附加所有被编辑的Config实体引用的相关DataField对象。 但是有一点皱纹。 您将需要告诉DbContext哪些实体是新的,哪些已修改。 由于DataField.Id属性将为0,因此可以轻松地从修改后的实体中分辨出新实体。但是,如何判断现有的DataField实体是否已返回不变? 这很重要,因为仅将DataField实体附加到DbContext会将它们置于上下文内的Unmodified状态。 因此,如果现有实体发生任何更改,则在提交上下文时这些更改将不会保留。

天真的方法要解决此问题,需要将其Id属性为非零的所有DataField实体设置为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时需要注意的各种事情。

另外,我强烈建议您查看以下书籍:

这些书中的每本书都讨论了您正在谈论的场景。 由于您首先使用代码,因此您可能要先阅读《代码优先》一书。

高温超导

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM