取消和存储操作的适当路由

Appropriate routing of the actions Cancel and Store

我有一个列出所有自行车的页面 (Bike.cshtml)。单击单个自行车时,我将转到编辑页面 (BikeEdit.cshtml)。在编辑器的底部,我有两个链接。

@Html.ActionLink("Cancel", "Bikes", "Home")
@Html.ActionLink("Update", "Bikes", "Home")

这两种情况都应该返回到列出自行车的页面。显然,在第二个中,我希望将模型对象的更改存储到数据库中。我很想通过像这样发送模型来解决它。

@Html.ActionLink("Cancel", "Bikes", "Home")
@Html.ActionLink("Update", "Bikes", "Home", @Model, null)

不过,我感觉到有更好的方法来处理它。管理自行车查看器控制器的节省有些令人不安。

我能想到的另一种方法是添加一个新动作,BikeSave,并在其中执行保存。但是,返回的视图实例不会基于 Bikes.cshtml,而是 BikeSave.cshtml。我可以想象我可以使用 RedirectToAction 但我不确定。我不想使用 "duct tape".

设计一些东西

所以我摇摇头无法决定...

当用户点击更新按钮时,您应该将表单提交到您的 HttpPost 操作方法,您将在其中更新您的数据库,然后重定向到 Home/Bikes 页面。

假设你的 GET 操作是这样的

public ActionResult BikeEdit(int id)
{
  var bikeEditVm=new BikeEditVm { Id=id};
  var bikeEntity = db.Bikes.FirstOrDefault(s=>s.Id==id);
  if(bikeEntity!=null)
  {
    bikeEditVm.ModelName=bikeEntity.ModelName;
    bikeEditVm.Color=bikeEntity.Color;   
    return View(bikeEditVm); 
  }
  return View("NotFound"); // return a bike not found view to user
}

其中BikeEditVm是编辑视图的视图模型,看起来像这样

public class BikeEditVm
{
  public int Id {set;get;}
  public string ModelName {set;get;}
  public string Color {set;get;}
}

在 BikeEditVm 的强类型视图中,您会将所有可编辑字段保存在 form 标签中

@model BikeEditVm
@using(Html.BeginForm())
{
  <label>ModelName</label>
  @Html.TextBoxFor(s=>s.ModelName)
  <label>Color</label>
  @Html.TextBoxFor(s=>s.Color)
  @Html.HiddenFor(s=>s.Id)
  <input type="submit" value="Update" />
}
@Html.ActionLink("Cancel","Bikes","Home")

您将有一个 HttpAction 方法来处理表单发布,您将从数据库中读取现有实体,更新您要更新的相关字段并将其保存回来。

[HttpPost]
public ActionResult BikeEdit(BikeEditVm model)
{
  var bikeEntity = db.Bikes.FirstOrDefault(s=>s.Id==model.id);
  if(bikeEntity!=null)
  {
    bikeEntity .ModelName = model.ModelName;
    bikeEntity .Color = model.Color;   
    db.Entry(bikeEntity).State=EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Bikes","Home");
  }
  return View("NotFound");
}

编辑: 回答 OP 在评论中为未来的读者提出的一些问题。

(1) I tested to skip [HttpPost] and it works still. Should it?

任何更新您的数据的东西都应该是一个 HttpPost method.otherwise,人们可以通过 url(GET 方法)访问您的操作方法并传递表单字段 name-values 并可以尝试更新您的数据。(如果存在,您的授权检查可能会阻止这种情况

(2) How does your Html.BeginForm() know where to route? I'm using Html.BeginForm(action, controller).

如果您不向 BeginForm 方法传递任何参数,它会将表单操作值设置为当前 url。例如:如果您在 customer/create GET 操作视图,您的表单将发布到 customer/create。您可以通过使用不同的重载来覆盖此行为,您可以在其中指定不同的操作 method/controller 名称。

(3) If I want a field to be passed up/down but not be editable/visible, should I use CSS to hide it? It'd be good to have a control for off-screen storage.

如果您不希望该字段是 editable/visible,请不要将其传递给您的视图。在您的视图模型中只包含您视图中真正需要的那些属性。阅读下一个关于如何防止过度发布的回复。

(4) Is it generally the best idea to have a specialized model for the view instead of using the one from EF?

是的。如果您使用由您的 ORM 创建的实体 类 在您的操作方法和视图之间传输数据,那么您正在制作一个紧密耦合的解决方案。如果您明天出于任何原因决定不使用 EF 作为数据访问层怎么办?你想去更新你所有的观点吗?您的视图模型特定于视图。因此,只保留视图所需的那些 properties/fields。这也将帮助您 .