为什么动作方法会得到错误的参数?
Why does the action method get wrong parameter?
我有用于编辑某些项目属性的 Action 方法和 View。
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin")]
public async Task<ActionResult> Edit(Item item)
{
if (ModelState.IsValid)
{
db.Entry(item).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.CatagorieId = new SelectList(db.Catagories, "ID", "Name", item.CatagorieId);
return View(item);
}
和
@model OpenOrderFramework.Models.Item
@using OpenOrderFramework.Extensions
@{
ViewBag.Title = "edit";
}
<h2>Editing</h2>
@using (Html.BeginForm())
{
<div class="form-horizontal">
<h4>The car</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.ID)
<-- etc -->
但是当我提交表单时出现错误
Store update, insert, or delete statement affected an unexpected number of rows (0).
我发现在操作方法中,已发布项目的 ID 始终为 0,即使该项目的真实 ID 不同。
为什么会这样?
获取操作方法:
// GET: Items/Edit/5
[Authorize(Roles = "Admin")]
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Item item = await db.Items.FindAsync(id);
if (item == null)
{
return HttpNotFound();
}
ViewBag.CatagorieId = new SelectList(db.Catagories, "ID", "Name", item.CatagorieId);
return View(item);
}
当您 post 表单时,对 HttpPost 操作方法的 http 调用是一个完全独立的 Http 请求,Entity framework 无法跟踪该实体。
正如 Darin 在评论中提到的,在 UI 层中混合实体 类 不是一个好主意。这使得它非常紧密地耦合。
您应该使用的是为您的视图创建和使用视图模型。视图模型只是 POCO 类,它特定于视图。
public class ItemViewModel
{
public int Id {set;get;}
public string Name {set;get;}
public List<SelectListItem> Categories { set;get;}
public int SelectedCategory {set;get;}
}
然后在您的 GET 操作中,从数据库中读取实体,创建视图模型的对象并将 属性 值设置为
public ActionResult Edit(int id)
{
var vm=new ItemViewModel { Id=id };
var item = db.Items.FirstOrDefault(s=>s.Id==id);
if(item!=null)
{
vm.Name = item.Name;
}
vm.Categories =db.Categories.Select(s=> new SelectListItem { Value=s.Id.ToString(),
Text=s.Name
}).ToList();
return View(vm);
}
并且您的视图将强类型化到您的视图模型
@model ItemViewModel
@using(Html.BeginForm())
{
@Html.DropdDownListFor(s=>s.SelectedCategory,Model.Categories,"Select")
@Html.HiddenFor(s=>s.Id)
@Html.TextBoxFor(s=>s.Name)
<input type="submit" />
}
并且在您的 HttpPost 操作中,从您的数据库中读取现有实体并更新您要更新的 属性 值。
[HttpPost]
public ActionResult Edit(ItemViewModel model)
{
if(ModelState.IsValid)
{
var item = d.Items.FirstOrDefault(s=>s.Id==model.Id);
item.Name = model.Name;
db.Entry(item).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
model.Categories =db.Categories.Select(s=>
new SelectListItem {
Value=s.Id.ToString(),
Text=s.Name }).ToList();
return View(model);
}
确保在访问代码中的实体/对象之前添加足够的 NULL 检查。
我有用于编辑某些项目属性的 Action 方法和 View。
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin")]
public async Task<ActionResult> Edit(Item item)
{
if (ModelState.IsValid)
{
db.Entry(item).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.CatagorieId = new SelectList(db.Catagories, "ID", "Name", item.CatagorieId);
return View(item);
}
和
@model OpenOrderFramework.Models.Item
@using OpenOrderFramework.Extensions
@{
ViewBag.Title = "edit";
}
<h2>Editing</h2>
@using (Html.BeginForm())
{
<div class="form-horizontal">
<h4>The car</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.ID)
<-- etc -->
但是当我提交表单时出现错误
Store update, insert, or delete statement affected an unexpected number of rows (0).
我发现在操作方法中,已发布项目的 ID 始终为 0,即使该项目的真实 ID 不同。
获取操作方法:
// GET: Items/Edit/5
[Authorize(Roles = "Admin")]
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Item item = await db.Items.FindAsync(id);
if (item == null)
{
return HttpNotFound();
}
ViewBag.CatagorieId = new SelectList(db.Catagories, "ID", "Name", item.CatagorieId);
return View(item);
}
当您 post 表单时,对 HttpPost 操作方法的 http 调用是一个完全独立的 Http 请求,Entity framework 无法跟踪该实体。
正如 Darin 在评论中提到的,在 UI 层中混合实体 类 不是一个好主意。这使得它非常紧密地耦合。
您应该使用的是为您的视图创建和使用视图模型。视图模型只是 POCO 类,它特定于视图。
public class ItemViewModel
{
public int Id {set;get;}
public string Name {set;get;}
public List<SelectListItem> Categories { set;get;}
public int SelectedCategory {set;get;}
}
然后在您的 GET 操作中,从数据库中读取实体,创建视图模型的对象并将 属性 值设置为
public ActionResult Edit(int id)
{
var vm=new ItemViewModel { Id=id };
var item = db.Items.FirstOrDefault(s=>s.Id==id);
if(item!=null)
{
vm.Name = item.Name;
}
vm.Categories =db.Categories.Select(s=> new SelectListItem { Value=s.Id.ToString(),
Text=s.Name
}).ToList();
return View(vm);
}
并且您的视图将强类型化到您的视图模型
@model ItemViewModel
@using(Html.BeginForm())
{
@Html.DropdDownListFor(s=>s.SelectedCategory,Model.Categories,"Select")
@Html.HiddenFor(s=>s.Id)
@Html.TextBoxFor(s=>s.Name)
<input type="submit" />
}
并且在您的 HttpPost 操作中,从您的数据库中读取现有实体并更新您要更新的 属性 值。
[HttpPost]
public ActionResult Edit(ItemViewModel model)
{
if(ModelState.IsValid)
{
var item = d.Items.FirstOrDefault(s=>s.Id==model.Id);
item.Name = model.Name;
db.Entry(item).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
model.Categories =db.Categories.Select(s=>
new SelectListItem {
Value=s.Id.ToString(),
Text=s.Name }).ToList();
return View(model);
}
确保在访问代码中的实体/对象之前添加足够的 NULL 检查。