[英]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
实体Attach
到DbContext
以便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.