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

本文关键字:取消 存储 路由 操作 | 更新日期: 2023-09-27 18:28:44

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

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

这两种情况都被认为会回到列出自行车的页面。显然,在第二个例子中,我希望将模型对象的更改存储到DB中。我很想通过发送这样的模型来解决这个问题。

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

然而,我感觉到有更好的方法来处理它。从自行车观看者的控制器中管理节省的钱有一些令人不安的地方。

我能想到的另一种方法是添加一个新的操作,BikeSave,并在其中执行保存。然而,返回的视图实例不会基于Bikes.cshtml,而是基于BikeSave.cshtml。我可以想象我可以使用RedirectToAction但我觉得不确定。我不想用"胶带"设计东西。

所以我摇摆不定。。。

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

当用户单击更新按钮时,您应该向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) 我测试跳过[HttpPost],它仍然有效。应该吗?

任何更新数据的操作都应该是HttpPost方法。否则,人们可以通过url(GET方法)访问您的操作方法,并传递表单字段名称值,还可以尝试更新您的数据。(如果存在,您的授权检查可能会阻止这种情况

(2) 您的Html.BeginForm()如何知道路由到哪里?我正在使用Html.BeginForm(操作,控制器)。

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

(3) 如果我希望一个字段被向上/向下传递,但不被可编辑/可见,我应该使用CSS来隐藏它吗?如果有一个控制屏幕外存储。

如果您不希望字段是可编辑/可见的,请不要将其事件传递到您的视图。在视图模型中只包含视图中真正需要的属性。阅读下一篇关于如何防止过度张贴的回复。

(4) 为视图,而不是使用EF中的视图?

是的。如果你使用ORM创建的实体类在操作方法和视图之间传输数据,那么你就是在制作一个紧密耦合的解决方案。如果您明天出于任何原因决定不使用EF作为您的数据访问层,该怎么办?你想去更新你的所有视图吗?视图模型是特定于某个视图的。因此,只保留视图所需的属性/字段。这也将有助于您防止过度加注。