MVC 5 - 如何首先使用 EF 代码更新关系 table
MVC 5 - How to update relational table using EF code first
我是 MVC 5 的新手,在弄清楚如何更新关系 table 时遇到了问题。我首先使用 EF 代码。我花了很多时间寻找解决方案,但我找不到与我的代码相关的任何内容,这就是为什么我别无选择,只能在这里询问,所以如果这个问题已经得到解答,我先表示歉意。
我在我的 Razor 视图中包含了关系 table,它工作得很好。但是,当我想更新 table 时,即使我当前的代码没有出错,它也不会更新。
我还尝试添加一个额外的 Bind[(Include = "Id,FirstName,LastName")],但这使用了 Booking FirstName 和 LastName。
我不确定我的方法是否是 "proper" 方法。我的逻辑告诉我,我需要从视图中获取数据并在控制器中检索它们,但我不知道如果我不能使用 Bind 或 db.Entry(item).State = EntityState.Modified?
Booking.cs
namespace Ventures.Innovation.InteractiveModel.Context
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class Bookings
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Bookings()
{
AttendingPeople = new HashSet<AttendingPeople>();
}
public int Id { get; set; }
[Required]
[StringLength(128)]
public string AspNetUserFk { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
[StringLength(100)]
public string FirstName { get; set; }
[Required]
[StringLength(50)]
public string LastName { get; set; }
public virtual AspNetUsers AspNetUsers { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<AttendingPeople> AttendingPeople { get; set; }
}
}
AttendingPeople.cs
namespace Ventures.Innovation.InteractiveModel.Context
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class AttendingPeople
{
public int Id { get; set; }
public int BookingId { get; set; }
[Required]
[StringLength(100)]
public string FirstName { get; set; }
[Required]
[StringLength(50)]
public string LastName { get; set; }
public virtual Bookings Bookings { get; set; }
}
}
控制器
// GET: AdminHome/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Bookings bookings = db.Bookings.Find(id);
if (bookings == null)
{
return HttpNotFound();
}
ViewBag.AspNetUserFk = new SelectList(db.AspNetUsers, "Id", "Email", bookings.AspNetUserFk);
var attendingPeople = db.AttendingPeople.Where(a => a.BookingId == id).ToList();
bookings.AttendingPeople = attendingPeople;
return View(bookings);
}
// POST: AdminHome/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,AspNetUserFk,Date,FirstName,LastName")] Bookings bookings)
{
if (ModelState.IsValid)
{
db.Entry(bookings).State = EntityState.Modified;
db.SaveChanges();
var editedAttendingPeople = db.AttendingPeople.Where(a => a.BookingId == bookings.Id).ToList();
foreach (var item in editedAttendingPeople)
{
db.Entry(item).State = EntityState.Modified;
}
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.AspNetUserFk = new SelectList(db.AspNetUsers, "Id", "Email", bookings.AspNetUserFk);
return View(bookings);
}
查看
@model Ventures.Innovation.InteractiveModel.Context.Bookings
@{
ViewBag.Title = "Edit booking";
}
<h2>Edit booking</h2>
<hr />
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)
</div>
<div class="form-group">
@Html.LabelFor(model => model.AspNetUserFk, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("AspNetUserFk", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.AspNetUserFk, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Date, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Date, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Date, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
</div>
</div>
@if (Model.AttendingPeople.Count > 0)
{
@Html.Label("Attending people")
foreach (var attendingPeople in Model.AttendingPeople)
{
<div class="form-group">
<div class="col-md-10">
@Html.LabelFor(modelItem => attendingPeople.FirstName, htmlAttributes: new { @class = "control-label col-md-5", @style = "padding-left: 0;" })
@Html.LabelFor(modelItem => attendingPeople.LastName, htmlAttributes: new { @class = "control-label col-md-5", @style = "padding-left: 0;" })
</div>
<div class="col-md-10">
@Html.EditorFor(modelItem => attendingPeople.FirstName, new { htmlAttributes = new { @class = "form-control col-md-5", @style = "display: initial;" } })
@Html.EditorFor(modelItem => attendingPeople.LastName, new { htmlAttributes = new { @class = "form-control col-md-5", @style = "display: initial;" } })
</div>
</div>
}
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save changes" class="btn btn-primary" />
</div>
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
我想将更新后的数据保存到数据库中的 AttendingPeople table,但没有任何反应。
感谢 JARRRRG 在这里帮助我。 :)
为了解决这个问题,我需要确保我的命名完全相同。显然这就是它 finds/binds 从视图到控制器的方式。我还需要确保我使用了 for 循环,以便集合可以区分对象。
这是我更新后的观点:
@if (Model.AttendingPeople.Count > 0)
{
@Html.Label("Attending people")
var attendingPeople = Model.AttendingPeople.ToArray();
foreach (int i = 0; i < attendingPeople.Length; i++)
{
@Html.HiddenFor(modelItem => attendingPeople[i].Id)
<div class="form-group">
<div class="col-md-10">
@Html.LabelFor(modelItem => attendingPeople[i].FirstName, htmlAttributes: new { @class = "control-label col-md-5", @style = "padding-left: 0;" })
@Html.LabelFor(modelItem => attendingPeople[i].LastName, htmlAttributes: new { @class = "control-label col-md-5", @style = "padding-left: 0;" })
</div>
<div class="col-md-10">
@Html.EditorFor(modelItem => attendingPeople[i].FirstName, new { htmlAttributes = new { @class = "form-control col-md-5", @style = "display: initial;" } })
@Html.EditorFor(modelItem => attendingPeople[i].LastName, new { htmlAttributes = new { @class = "form-control col-md-5", @style = "display: initial;" } })
</div>
</div>
}
}
这是我的新编辑:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,AspNetUserFk,Date,FirstName,LastName")] Bookings bookings, ICollection<AttendingPeople> attendingPeople)
{
if (ModelState.IsValid)
{
db.Entry(bookings).State = EntityState.Modified;
db.SaveChanges();
foreach (var item in attendingPeople)
{
item.BookingId = bookings.Id;
db.Entry(item).State = EntityState.Modified;
}
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.AspNetUserFk = new SelectList(db.AspNetUsers, "Id", "Email", bookings.AspNetUserFk);
bookings = db.Bookings.Include(at => at.AttendingPeople).SingleOrDefault(b => b.Id == bookings.Id)
return View(bookings);
}
我是 MVC 5 的新手,在弄清楚如何更新关系 table 时遇到了问题。我首先使用 EF 代码。我花了很多时间寻找解决方案,但我找不到与我的代码相关的任何内容,这就是为什么我别无选择,只能在这里询问,所以如果这个问题已经得到解答,我先表示歉意。
我在我的 Razor 视图中包含了关系 table,它工作得很好。但是,当我想更新 table 时,即使我当前的代码没有出错,它也不会更新。 我还尝试添加一个额外的 Bind[(Include = "Id,FirstName,LastName")],但这使用了 Booking FirstName 和 LastName。 我不确定我的方法是否是 "proper" 方法。我的逻辑告诉我,我需要从视图中获取数据并在控制器中检索它们,但我不知道如果我不能使用 Bind 或 db.Entry(item).State = EntityState.Modified?
Booking.cs
namespace Ventures.Innovation.InteractiveModel.Context
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class Bookings
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Bookings()
{
AttendingPeople = new HashSet<AttendingPeople>();
}
public int Id { get; set; }
[Required]
[StringLength(128)]
public string AspNetUserFk { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
[StringLength(100)]
public string FirstName { get; set; }
[Required]
[StringLength(50)]
public string LastName { get; set; }
public virtual AspNetUsers AspNetUsers { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<AttendingPeople> AttendingPeople { get; set; }
}
}
AttendingPeople.cs
namespace Ventures.Innovation.InteractiveModel.Context
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class AttendingPeople
{
public int Id { get; set; }
public int BookingId { get; set; }
[Required]
[StringLength(100)]
public string FirstName { get; set; }
[Required]
[StringLength(50)]
public string LastName { get; set; }
public virtual Bookings Bookings { get; set; }
}
}
控制器
// GET: AdminHome/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Bookings bookings = db.Bookings.Find(id);
if (bookings == null)
{
return HttpNotFound();
}
ViewBag.AspNetUserFk = new SelectList(db.AspNetUsers, "Id", "Email", bookings.AspNetUserFk);
var attendingPeople = db.AttendingPeople.Where(a => a.BookingId == id).ToList();
bookings.AttendingPeople = attendingPeople;
return View(bookings);
}
// POST: AdminHome/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,AspNetUserFk,Date,FirstName,LastName")] Bookings bookings)
{
if (ModelState.IsValid)
{
db.Entry(bookings).State = EntityState.Modified;
db.SaveChanges();
var editedAttendingPeople = db.AttendingPeople.Where(a => a.BookingId == bookings.Id).ToList();
foreach (var item in editedAttendingPeople)
{
db.Entry(item).State = EntityState.Modified;
}
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.AspNetUserFk = new SelectList(db.AspNetUsers, "Id", "Email", bookings.AspNetUserFk);
return View(bookings);
}
查看
@model Ventures.Innovation.InteractiveModel.Context.Bookings
@{
ViewBag.Title = "Edit booking";
}
<h2>Edit booking</h2>
<hr />
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)
</div>
<div class="form-group">
@Html.LabelFor(model => model.AspNetUserFk, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("AspNetUserFk", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.AspNetUserFk, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Date, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Date, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Date, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
</div>
</div>
@if (Model.AttendingPeople.Count > 0)
{
@Html.Label("Attending people")
foreach (var attendingPeople in Model.AttendingPeople)
{
<div class="form-group">
<div class="col-md-10">
@Html.LabelFor(modelItem => attendingPeople.FirstName, htmlAttributes: new { @class = "control-label col-md-5", @style = "padding-left: 0;" })
@Html.LabelFor(modelItem => attendingPeople.LastName, htmlAttributes: new { @class = "control-label col-md-5", @style = "padding-left: 0;" })
</div>
<div class="col-md-10">
@Html.EditorFor(modelItem => attendingPeople.FirstName, new { htmlAttributes = new { @class = "form-control col-md-5", @style = "display: initial;" } })
@Html.EditorFor(modelItem => attendingPeople.LastName, new { htmlAttributes = new { @class = "form-control col-md-5", @style = "display: initial;" } })
</div>
</div>
}
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save changes" class="btn btn-primary" />
</div>
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
我想将更新后的数据保存到数据库中的 AttendingPeople table,但没有任何反应。
感谢 JARRRRG 在这里帮助我。 :)
为了解决这个问题,我需要确保我的命名完全相同。显然这就是它 finds/binds 从视图到控制器的方式。我还需要确保我使用了 for 循环,以便集合可以区分对象。
这是我更新后的观点:
@if (Model.AttendingPeople.Count > 0)
{
@Html.Label("Attending people")
var attendingPeople = Model.AttendingPeople.ToArray();
foreach (int i = 0; i < attendingPeople.Length; i++)
{
@Html.HiddenFor(modelItem => attendingPeople[i].Id)
<div class="form-group">
<div class="col-md-10">
@Html.LabelFor(modelItem => attendingPeople[i].FirstName, htmlAttributes: new { @class = "control-label col-md-5", @style = "padding-left: 0;" })
@Html.LabelFor(modelItem => attendingPeople[i].LastName, htmlAttributes: new { @class = "control-label col-md-5", @style = "padding-left: 0;" })
</div>
<div class="col-md-10">
@Html.EditorFor(modelItem => attendingPeople[i].FirstName, new { htmlAttributes = new { @class = "form-control col-md-5", @style = "display: initial;" } })
@Html.EditorFor(modelItem => attendingPeople[i].LastName, new { htmlAttributes = new { @class = "form-control col-md-5", @style = "display: initial;" } })
</div>
</div>
}
}
这是我的新编辑:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,AspNetUserFk,Date,FirstName,LastName")] Bookings bookings, ICollection<AttendingPeople> attendingPeople)
{
if (ModelState.IsValid)
{
db.Entry(bookings).State = EntityState.Modified;
db.SaveChanges();
foreach (var item in attendingPeople)
{
item.BookingId = bookings.Id;
db.Entry(item).State = EntityState.Modified;
}
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.AspNetUserFk = new SelectList(db.AspNetUsers, "Id", "Email", bookings.AspNetUserFk);
bookings = db.Bookings.Include(at => at.AttendingPeople).SingleOrDefault(b => b.Id == bookings.Id)
return View(bookings);
}