简体   繁体   English

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

[英]Updating complex model binding EF5 ASP.NET MVC4

I'm having a difficult time figuring out how to update my entities and their related data. 我很难弄清楚如何更新实体及其相关数据。 Using Lazyloading.. 使用延迟加载

I have the following entity models 我有以下实体模型

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; }
}

With the corresponding view models. 带有相应的视图模型。 I've stripped them down, removed validations and such. 我已经将其剥离,删除了验证等。

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; }
}

In my Edit.cshtml form I dynamically add new datafields, and when I post the form, they are properly deserialised to ConfigViewModel.DataFields. 在我的Edit.cshtml表单中,我动态添加了新的数据字段,并且在发布表单时,已将它们正确反序列化为ConfigViewModel.DataFields。 So long everything is working. 这么久,一切正常。 But how do I convert these models, and update the entitymodels? 但是,如何转换这些模型并更新实体模型? If I post new datafields, their id's will be 0, and they should be added, but the ones that already have an Id, should be updated.. I don't know how to do this, and can't find anything related, or that I could understand. 如果我发布新的数据字段,则它们的ID将为0,应添加它们,但是应该更新已经具有ID的ID。我不知道如何执行此操作,并且找不到任何相关的内容,还是我能理解的。

I have the following in my ConfigController. 我的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);
    }
}

In my repository I have: 在我的存储库中,我有:

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

My Edit.cshtml form looks like 我的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>
}

It looks like a couple of things are happening here. 似乎这里发生了几件事。

If I understand your data structures correctly, you have a Config object that has zero or more DataField objects associated with it. 如果我正确理解您的数据结构,则您有一个Config对象,该对象具有零个或多个与其关联的DataField对象。

The Edit page of your application for editing Config objects allows you to add new DataField items or modify existing DataField items. 用于编辑Config对象的应用程序的“编辑”页面允许您添加新的 DataField项目 修改现有的 DataField项目。

I'm assuming that in the commented section of your example: 我假设在您的示例的注释部分中:

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

that you're translating the View Models back to your domain objects. 您正在将视图模型转换回您的域对象。

Now I'm going to assume that you are using a per-request lifetime for the DbContext , as that's most typical in these scenarios. 现在,我假设您正在为DbContext使用每个请求的生存期,因为在这些情况下这是最典型的。 So, on each web request, a new DbContext is instantiated as part of the instantiation chain of the MVC Controller and its dependencies (eg services, repositories, unit of work, etc.). 因此,在每个Web请求上,一个新的DbContext被实例化为MVC控制器及其依赖关系(例如服务,存储库,工作单元等)的实例化链的一部分。 So on this new request for editing Config objects, the DbContext is empty—it has no knowledge of any objects because it's a brand new DbContext . 因此,对于这个新的编辑Config对象的请求, DbContext为空-它不知道任何对象,因为它是一个全新的DbContext

At this point, you need to Attach the Config entity to the DbContext so that the DbContext will start tracking it. 此时,您需要Attach Config实体AttachDbContext以便DbContext开始对其进行跟踪。 If anything changed about the Config entity (eg was the name changed, or were new DataField objects added to the collection?), you will need to set the state of the entity within the DbContext to Modified (this you have done in your example above). 如果对Config实体进行了任何更改(例如,名称是否更改,或者是否向集合中添加了新的DataField对象?),则需要将DbContext中的实体状态设置为Modified (在上面的示例中已完成此操作) )。

Attaching the Config entity to the DbContext will also result in attaching all the related DataField objects that are referenced by the edited Config entity. Config实体附加到DbContext还将导致附加所有被编辑的Config实体引用的相关DataField对象。 But there's a slight wrinkle. 但是有一点皱纹。 You will need to tell the DbContext which entities are new, and which are modified. 您将需要告诉DbContext哪些实体是新的,哪些已修改。 You can easily tell new entities from modified entities because the DataField.Id property will be 0. But how do you tell if an existing DataField entity has been returned unchanged? 由于DataField.Id属性将为0,因此可以轻松地从修改后的实体中分辨出新实体。但是,如何判断现有的DataField实体是否已返回不变? This is important, because simply attaching the DataField entities to the DbContext puts them in an Unmodified state within the context. 这很重要,因为仅将DataField实体附加到DbContext会将它们置于上下文内的Unmodified状态。 So, if there were any changes on an existing entity, those changes would not be persisted when committing the context. 因此,如果现有实体发生任何更改,则在提交上下文时这些更改将不会保留。

A naive approach to solve this problem would entail setting all DataField entities whose Id property is non-zero to the Modified state. 天真的方法要解决此问题,需要将其Id属性为非零的所有DataField实体设置为Modified状态。 This will increase load on the database (but for a small application, this will be negligible). 这将增加数据库的负载(但是对于小型应用程序,这可以忽略不计)。 However, if you have any triggers or some other mechanism for auditing when records are created or updated, this is not a good solution. 但是,如果在创建或更新记录时有任何触发器或其他某种审核机制,则这不是一个好的解决方案。 Assuming you are not performing auditing, the naive approach may work well: 假设您没有执行审核,那么幼稚的方法可能会很好地工作:

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();
}

Again, this is a naive approach that should generally work well for small applications. 同样,这是一种幼稚的方法,通常应适用于小型应用程序。 At the very least, it should give you a better idea of the kinds of things you need to be aware of when working with Entity Framework in a disconnected N-Tier scenario. 至少,它应该使您更好地了解在断开的N层场景中使用Entity Framework时需要注意的各种事情。

Also, I highly recommend you check out the following books: 另外,我强烈建议您查看以下书籍:

Each of those books discusses the scenario you're talking about. 这些书中的每本书都讨论了您正在谈论的场景。 You may want to start with the Code First book since you are using code first. 由于您首先使用代码,因此您可能要先阅读《代码优先》一书。

HTH 高温超导

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

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