【问题标题】:ASP.NET MVC: where to keep entity being edited by userASP.NET MVC:保存用户正在编辑的实体的位置
【发布时间】:2009-10-23 15:59:52
【问题描述】:

这是一个简单的问题:用户希望以网格方式编辑产品:选择并单击添加,选择并单击添加...他们看到更新的产品列表...然后单击“完成”并保存订单.

但是,每个“添加”必须去服务器,因为它涉及服务器端验证。此外,验证是在域实体内部(比如 Order)——也就是说,要进行验证,我需要调用 order.Add(product),然后 order 决定它是否可以添加产品。

问题是,如果我将产品添加到订单中,它会保留更改,因此即使用户不点击“完成”,更改仍然存在!

好的,我可能不应该在用户单击完成之前修改订单。但是,我该如何验证产品呢?这应该由订单实体完成 - 如果产品已经添加,如果产品与其他产品不冲突,等等。

另一个问题是,我必须将产品添加到订单中并根据其新状态“重建视图/HTML”(因为它可能会发生很大变化)。但是,如果我不坚持订单更改,则下一次添加每次都会从相同的订单开始,而不是从更新的订单开始。也就是说,我需要以某种方式跟踪订单的更改。

我看到了几种解决方案:

  1. 每次用户单击添加时,从数据库中检索订单,并添加所有新产品(从页面),但不要持久化,只需返回视图(订单)。问题是我无法从 POST /Edit 重定向到 GET /Edit - 因为所有数据只存在于 POST 数据中,而 GET 会丢失它。这意味着刷新页面不能以一种很好的方式工作(F5 并且您收到重复的请求,更不用说浏览器的对话框了))。
    • 嗯,我想我可以使用 TempData(和 MvcContrib 帮助程序)重定向到 GET。因此,在 POST 到 /Edit 之后,我处理业务逻辑,获取新数据以供查看,并从通过 TempData 传递数据的 MvcContrib 执行 RedirectToAction(data)。但是由于 TempDate 是... temp... 在 F5 之后所有数据都丢失了。不工作。该死的数据应该以这种或另一种方式存储在某个地方。
  2. 将“编辑对象”与 POST 数据(订单、新产品信息)一起存储在 Session 中。这也可以是数据库。一种“当前项目 - 每页类型”。因此页面将从该存储中获取订单 ID 和当前添加的产品。但是从多个页面进行编辑是有问题的。而且我不喜欢在 Session 中存储临时/当前对象。
  3. 将产品标记为“已确认” - 如果我们执行 /order/show,我们首先从订单中清除所有未确认的产品。丑陋而混乱的逻辑。
  4. 制作一份订单副本 - 一份临时的 - 并让 /Edit 使用它。确认会将更改从临时订单移动到持久化。很多丑陋的工作。
  5. 也许是一些 AJAX 魔法? IE。 “添加”按钮不会重新加载页面,只会将新的 + 已添加的产品发送到服务器,服务器将作为订单验证。添加(产品 + 新产品)但 不会 保留更改,只会返回更新的订购信息以重新构建网格。但 Refresh/F5 会杀死所有用户输入的信息。
  6. 还有什么?

这个问题常见吗?你如何解决类似的问题?最佳做法是什么?

【问题讨论】:

  • 我已对您最近的 cmets 发表了补充评论。

标签: asp.net-mvc domain-driven-design


【解决方案1】:

这在很大程度上取决于您如何实现对象/验证,但您的选项 5 可能是最好的主意。如果 AJAX 不是你的菜,你可以通过将已添加但未保存的条目的相关数据写入隐藏字段来完成同样的事情。

换句话说,流程最终是这样的:

  1. 用户输入一个项目。

  2. 项目被发送到服务器并进行验证。视图与用户在隐藏字段中输入的数据一起返回。

  3. 用户输入第二个项目。

  4. 项目被发送到服务器,并且两个项目都经过验证。视图与隐藏字段中的两个项目的数据一起返回。

  5. 等。

就 F5/Refresh 杀死输入的数据而言...根据我的经验,这不是什么大问题。一个更紧迫的问题是后退/前进按钮,需要使用真正简单的历史记录之类的东西进行管理。

如果您确实想让页面在刷新后继续工作,您需要执行以下操作之一:

  1. 将记录保存到数据库中,以某种方式与当前用户相关联。
  2. 将记录保存到会话中。
  3. 将记录保存到查询字符串中。

这些是唯一可以通过重定向和刷新持续存在的存储位置。

【讨论】:

  • Ajax 是我的东西,我不需要隐藏 - 我实际上需要向用户显示数据(即用户输入 Product1,我还需要显示价格和与其他产品的关系)命令)。好吧,也许F5不是问题,我需要与客户讨论。但总的来说,这会很烦人(至少对我来说)。我会用你建议的方式更新问题(坚持)。
  • 另外,您提到无法单击刷新按钮很烦人,这让我有些困惑。您是否在填写表格中途时定期刷新页面?
  • 抱歉,我一定遗漏了关于这些隐藏字段的一些要点……使用字段存储数据是我列出的选项#1。问题是 F5 再次向服务器发送最后一个请求,这将导致重复数据。嗯,我想我可以使用 TempData 解决方法(请参阅更新)。至于刷新,假设您不小心按下了它并丢失了所有输入的数据(使用 AJAX);或者你用它来“重置”表单——就像我经常做的那样——而是得到对话框和重复的 POST 到服务器——烦人。
  • 嗯,TempData 显然行不通。好吧,我希望看到一个常见问题的通用解决方案,但似乎并不常见......
  • 对于隐藏字段,我已经删除了我的评论。听起来你知道我在说什么,但我误解了你的评论。
【解决方案2】:

如果我是你,我会想出类似于选项 5 的东西。既然你说你对 Ajax 很满意,你可以试试这个。但在您这样做之前,您应该将您的验证逻辑移到 Order.Add() 方法之外。也许您可以将其移至另一个名为 Validate() 的公共函数,该函数返回一个布尔值。而且您仍然可以在 Add() 方法中调用相同的 Validate(),从而在添加订单之前进行必要的验证。

  1. 尝试在客户端进行验证。如果你使用 jQuery,你可以使用 jquery validate 插件。但是,如果由于某种原因(例如当您需要针对数据库验证内容时)这是不可能的。您应该在服务器端进行验证,并返回一个带有“成功”布尔标志和可选消息的 JSON 对象,这只是一种标记数据有效的方法。只有在之前的订单有效时,您才允许用户添加新产品。
  2. 当用户点击完成时,将产品发送到服务器并再次进行验证,但在此往返过程中保持订单。

现在,如果我对此有完整的发言权,我什至不会在添加/编辑产品时进行验证。每当客户点击完成时,我都会进行验证。那将是最简单的解决方案。但是,也许我错过了什么。

【讨论】:

  • 这不仅仅是验证,它是实体更改...例如,当您添加产品时,其他(添加的)产品会重新计算其“伙伴”计数...应该有一个服务器调用作为在客户端脚本中重写业务规则并不好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多