我正在开发我的第一个 ASP.NET MVC(版本 3 的测试版)应用程序(使用 EF4),并且我正在为一些关于保存新记录和更新现有记录的约定而苦苦挣扎。我正在使用标准路线映射。
当用户进入 /session/Evaluate 页面时,他们可以输入新记录并保存。我有一个这样定义的动作:
[ActionName("Evaluate")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EvaluateSave(EvaluteSessionViewModel evaluatedSession)
{
}
当他们保存时,我从视图模型中抓取一个实体并将其附加到我的上下文并保存。到目前为止,一切都很好。现在我希望用户能够通过 url /session/Evaluate/1 编辑此记录,其中“1”是记录 ID。
编辑:我将我的 EF 实体作为属性附加到视图模型。
如果我像这样添加一个重载方法(这样我就可以自动检索“1”部分)。
[ActionName("Evaluate")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EvaluateSave(ID, EvaluteSessionViewModel evaluatedSession)
{
}
我收到“当前对控制器类型 'SessionsController' 的操作 'Evaluate' 的请求在以下操作之间不明确”错误。我不确定为什么它们会模棱两可,因为它们对我来说看起来很独特。
我决定暂时跳过这个问题,看看是否可以让它更新现有记录,所以我注释掉了没有 ID 参数的 EvaluateSave。
我想做的是:
// Load the original entity from EF
// Rebind the postback so that the values posted update the entity
// Save the result
由于实体被填充为参数(评估会话),因此重新绑定发生得太快了。但是当我查看我想采用的方法时,我意识到它会打开我的代码以进行黑客攻击(因为用户可以在发布的后台页面中添加字段,并且这些可以覆盖我在实体中设置的值)。
所以看来我不得不手动检查每个字段以查看它是否已更改,如果已更改,请更新它。像这样的东西:
if (evaluatedSession.MyEntity.myField <> savedSession.myField)
savedSession.myField = evaluatedSession.MyEntity.myField;
或者,保存实体的副本并确保所有非用户可编辑的实体都没有更改。呸。
所以两个问题:
第一:如何消除重载方法的歧义?
第二:有没有更好的方法来处理更新以前保存的记录?
编辑:我想我可以使用 Automapper 之类的东西......
编辑 9/22/2010 - 好的,看起来这应该与两个项目的组合一起使用:您可以通过 [Bind(Exclude="field1,field2" )] 属性在类级别或作为进行保存的方法的一部分,例如。
public ActionResult EvaluateSave([Bind(Exclude="field1")] EvaluateSessionViewModel evaluatedSession)
从 EF 方面来说,您应该能够使用上下文中的 ApplyCurrentValues() 方法,例如。
context.ApplyCurrentValues(savedEval.EntityKey.EntitySetName, evaluatedSession);
当然,这似乎对我不起作用。我不断收到“在 ObjectStateManager 中找不到具有与所提供对象的键匹配的键的对象。验证所提供对象的键值是否与必须应用更改的对象的键值匹配。”。
我尝试附加我刚刚加载的原始实体,以防它由于某种原因没有附加到上下文中(在 ApplyCurrentValues 之前):
context.AttachTo(savedEval.EntityKey.EntitySetName, savedEval);
它仍然失败。我猜它与 MVC 创建的 EF 实体对象的类型有关(也许它的填充不足以让 EF4 对其进行任何处理?)。我曾希望启用 .NET 框架逐步遍历它以查看它试图做什么,但似乎 EF4 不是交易的一部分。我用 Reflector 查看了它,但我很难想象正在发生的事情。