1

我一直在环顾四周,无法完全找到答案。我在我的编辑视图中使用ViewModel,以便我可以为某些下拉列表设置值。现在,当我去更新我的数据库时,我不知道如何更新数据库记录。我猜我可以创建一个新的实体对象,做一个查找,然后更新基于从窗体传入的ViewModel的每个属性,但这确实看起来像很多手动工作。使用ViewModel和Entity Framework 6更新实体?

这里我在编辑视图中使用了VeiwModel。

@model CPPCustomerCall.ViewModels.CustomerCallVM 

这是我的控制器的ActionResult。我改变了ActionResult的对象类型,以取代CustomerCallVM而不是自动生成的CustomerCall。我假设编辑视图的模型是ViewModel,这是ActionResult将接收的对象的类型。但是,我的ViewModel有更多的属性,实体模型不需要更新记录。如何在这个ActionResult中更新我的数据库记录?

[HttpPost] 
[ValidateAntiForgeryToken] 
public async Task<ActionResult> Edit([Bind(Include = "Id,CustomerName,Subject,PhoneNumber,CallMessage,CallDate,Status,CallNotes")] CustomerCallVM customerCall) 
{ 
    if (ModelState.IsValid) 
    { 
     db.Entry(customerCall).State = EntityState.Modified; 
     await db.SaveChangesAsync(); 
     return RedirectToAction("Index"); 
    } 
    return View(customerCall); 
} 

回答

4

首先,Bind和视图模型是相互排斥的。如果你不想让某件事有资格被修改,那么它不应该放在你的视图模型上。除此之外,视图模型与实体不同,它们不能直接保存。因此,总会有一些介入将您发布的值映射回实体,这意味着您可以有选择地不映射某些不应该映射的属性,而不管它们是否已发布。长短,摆脱Bind的东西。这只是别的要维护和潜在错误的巨大来源。

这就是说,你的代码是可行的;您只是错过了将视图模型中的数据映射回实体的关键部分。首先,你需要让你有一个基地,从数据库中读取实体从工作:

var customerCall = db.CustomerCalls.Find(id); 
if (customerCall == null) 
{ 
    return new HttpNotFoundResult(); 
} 

FWIW,你的编辑路线应包括路线编号,根据REST约定。以下REST并不是严格要求的,但它当然是推荐的。虽然遵循REST的Web应用程序并不意味着它是一个很好的应用程序,但坚持休息通常是设计和编写得不好的应用程序的明确标志。

然后,你映射你的属性。您可以手动执行此操作:

customerCall.CustomerName = model.CustomerName; 
// etc. 

或者你可以使用库像AutoMapper

mapper.Map(model, customerCall); 

AutoMapper需要一些初始设置,使这种神奇的工作,当然,所以审查文档,如果你走这样一条路。手动映射更容易,但更繁琐和重复。

+0

谢谢。绑定的东西是自动生成的,我记得从Channel9读了一些教程,我相信他们建议使用它来避免过度发布。无论哪种方式,我没有删除问题,因为它看起来像额外的工作,至少在这种情况下可能是矫枉过正。至于其他代码,这听起来像我需要创建一个新的实体对象,并从传入的ViewModel中映射属性。我认为这是处理它的一种方式,但似乎是额外代码的潜力。我看了一次AutoMapper,但也阅读了远离它。 – Caverman

+1

小心你阅读的内容。那里有很多不好的信息。AutoMapper就好,如果你正确使用它。当你开始过度依赖它时,问题就随之而来。 “绑定”的东西是微软为遗憾设计而抱歉的尝试。事实是,一个实体不是一个模型,使用相同的类来发布数据以保持数据是没有意义的。多年来,微软一直在推动这种不好的做法,用“绑定”快速修复的方式来解决巨大的安全问题。 –

0
[HttpPost] 
[ValidateAntiForgeryToken] 
public async Task<ActionResult> Edit([Bind(Include = "Id,CustomerName,Subject,PhoneNumber,CallMessage,CallDate,Status,CallNotes")] CustomerCallVM customerCall) 
{ 
    if (ModelState.IsValid) 
    { 
     // Find The record you need 
     var dbObj = CustomerCalls.FirstOrDefault(x=> x.id = customerCall.id); 
     //Check if null 
     if(dbObj == null) dbObj = new CustomerCall(); 

     /// Map your properties 

     // Add object to the stack 
     if(dbObj.id == 0){ 
     CustomerCalls.Add(dbObj); 
     }else{ 
     CustomerCalls.Update(dbObj); 
     } 

    await db.SaveChangesAsync(); 
    return RedirectToAction("Index"); 
    } 
    return View(customerCall); 
}