ASP.NET MVC保存新记录更新现有记录约定

时间:2010-09-20 14:34:50

标签: entity-framework-4 asp.net-mvc-3

我正在开发我的第一个ASP.NET MVC(beta版本3)应用程序(使用EF4),我正在努力解决一些关于保存新记录和更新现有记录的约定。我正在使用标准路线映射。

当用户进入页面/会话/评估时,他们可以输入新记录并保存。我有一个像这样定义的动作:

[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'的当前操作请求'评估'在以下操作之间是不明确的”错误。我不确定为什么他们模棱两可,因为他们看起来很独特。

我决定暂时跳过这个问题并查看是否可以让它更新现有记录,所以我注释掉了没有ID参数的EvaluateSave。

我想做的是:

// Load the original entity from EF
// Rebind the postback so that the values posted update the entity
// Save the result

由于实体被填充为参数(evaluateSession),因此重新绑定过早发生。但是当我看到我想采取的方法时,我意识到它会将我的代码打开以进行黑客攻击(因为用户可以在已发布的后页中添加字段,这些可以覆盖我在实体中设置的值)。 / p>

因此,似乎我不得不手动检查每个字段以查看它是否已更改,如果已更改,请更新它。像这样:

if (evaluatedSession.MyEntity.myField <> savedSession.myField)
   savedSession.myField = evaluatedSession.MyEntity.myField;

或者,保存实体的副本,并确保没有任何非用户可编辑的实体已更改。呸。

所以有两个问题:

首先:如何消除重载方法的歧义?

第二:有没有更好的方法来处理更新以前保存的记录?

编辑:我想我可以使用像Automapper这样的东西......

编辑2010年9月22日 - 好了,看起来这应该可以使用两个项目的组合:您可以通过[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看了它,但是我想象一下发生了什么事情有点困难。

1 个答案:

答案 0 :(得分:1)

嗯,它的工作方式是每个httpverb只能有一个方法名称。所以最简单的方法是创建一个新的动作名称。新记录的“创建”和现有记录的“编辑”。

您可以使用AntiForgeryToken(http://msdn.microsoft.com/en-us/library/dd492767.aspx)来验证数据。它并没有阻止所有黑客攻击,但这是一个额外的好处。

其他

每个httpverb只能有一个操作名称的原因是因为模型绑定器只尝试对绑定进行建模,并且实际上不是特定于类型的。如果你有两个方法具有相同的动作名称和两个不同类型的参数,它不能只是尝试找到最佳匹配,因为你的意图可能显然是一件事,而程序只看到某种最佳匹配。例如,您可能有一个参数Id和一个包含属性Id的模型,它可能不知道您打算使用哪个。