我很难搞清楚如何更新我的实体及其相关数据。使用Lazyloading ..
我有以下实体模型
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的那些应该被更新.. 我不知道该怎么做,也找不到任何相关的东西,或者我能理解的东西。
我的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>
}
答案 0 :(得分:0)
看起来这里发生了一些事情。
如果我正确理解了您的数据结构,那么您有一个Config
对象,其中包含零个或多个DataField
个对象。
您的应用编辑页面用于修改Config
个对象,您可以添加新 DataField
项或 修改现有 DataField
项。
我假设在您的示例的评论部分中:
// Do Something with the DataFields
// config.DataFields
您正在将视图模型转换回您的域对象。
现在我假设您正在使用DbContext
的每请求生命周期,这在这些情况下是最典型的。因此,在每个Web请求上,新的DbContext
被实例化为MVC控制器的实例化链及其依赖性(例如,服务,存储库,工作单元等)的一部分。因此,对于编辑Config
个对象的新请求,DbContext
为空 - 它不知道任何对象,因为它是一个全新的DbContext
。
此时,您需要Attach
Config
实体加DbContext
,以便DbContext
开始跟踪它。如果有关Config
实体的任何更改(例如,名称已更改,或者新的DataField
对象是否已添加到集合中?),则需要在{{1}内设置实体的状态} DbContext
(这是你在上面的例子中所做的)。
将Modified
实体附加到Config
也会导致附加已编辑的DbContext
实体引用的所有相关DataField
个对象。但是有轻微的皱纹。您需要告诉Config
哪些实体是新的,哪些是经过修改的。您可以轻松地从已修改的实体中告知新实体,因为DbContext
属性将为0.但是,如何判断现有DataField.Id
实体是否未更改?这很重要,因为只需将DataField
实体附加到DataField
即可将其置于上下文中的DbContext
状态。因此,如果现有实体有任何更改,那么在提交上下文时这些更改将不会保留。
解决此问题的简单方法是将Unmodified
属性为非{0}的所有DataField
实体设置为Id
状态。这将增加数据库的负载(但对于小型应用程序,这可以忽略不计)。但是,如果在创建或更新记录时有任何触发器或其他一些审核机制,则这不是一个好的解决方案。假设您没有执行审计,那么天真的方法可能会很好用:
Modified
同样,这是一种天真的方法,通常应该适用于小型应用程序。至少,它应该让您更好地了解在断开连接的N层方案中使用Entity Framework时需要注意的事项。
此外,我强烈建议您查看以下书籍:
每本书都讨论了你所谈论的场景。您可能希望从Code First书开始,因为您首先使用代码。
HTH