【问题标题】:ASP.NET MVC save new record verse update existing record conventionsASP.NET MVC 保存新记录与更新现有记录约定
【发布时间】:2010-09-20 14:34:49
【问题描述】:

我正在开发我的第一个 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 之类的东西...

编辑 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 观察了它,但我有点难以想象正在发生的事情。

【问题讨论】:

  • 好的,看起来绕过重载方法(在我的情况下)的一种简单方法是只创建一个允许可以为空的 int 的方法,如下所示: public ActionResult EvaluateSave(int? ID, EvaluateSessionViewModel evaluateSession )
  • 是的,你可以这样做。我不会推荐它,因为这种类型的假设可能会根据模型而改变。例如,如果您的 EvaluateSessionViewModel 包含同名的属性。或者您有一个名称为 ID 的 cookie 或任何数量的不同事物仍会尝试填充 ID 值。

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


【解决方案1】:

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

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

附加

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 2013-09-25
    • 1970-01-01
    相关资源
    最近更新 更多