MVC 5 - 如何首先使用 EF 代码更新关系表

Posted

技术标签:

【中文标题】MVC 5 - 如何首先使用 EF 代码更新关系表【英文标题】:MVC 5 - How to update relational table using EF code first 【发布时间】:2019-11-11 23:48:09 【问题描述】:

我对 MVC 5 比较陌生,并且在弄清楚如何更新关系表时遇到了问题。我首先使用 EF 代码。我花了很多时间寻找解决方案,但我找不到任何与我的代码相关的东西,这就是为什么我除了在这里问之外别无选择,所以如果这个问题已经得到解答,我先道歉。

我将关系表包含在我的 Razor 视图中,效果非常好。但是当我想更新表格时,即使我当前的代码没有错误,它也不会更新。 我还尝试添加一个额外的 Bind[(Include = "Id,FirstName,LastName")],但这使用了 Booking FirstName 和 LastName。 我不确定我的方法是否是“正确的”方法。我的逻辑告诉我,我需要从视图中获取数据并在控制器中检索它们,但我不知道如果我不能使用 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 表中,但没有任何反应。

【问题讨论】:

好的,我现在知道代码:db.Entry(item).State = EntityState.Modified;实际上没有做任何事情,因为它没有更新。我不明白的是,即使我成功地将AttendingPeople 添加到Bookings,并且能够在视图中执行循环,我也没有从视图中得到任何东西到控制器,这意味着bookings.AttendingPeople。计数为 0。我想我需要检索 AttendingPeople 数据并将它们发送到控制器,但是如何? 到目前为止花了 2 天时间。我注意到 FormCollection 只有 1 个参加人[0].姓氏。但仍然没有更接近解决方案。 您的表单是否按预期绑定回控制器操作?你的问题很窄,但你的代码示例很广泛。我注意到的一件事是在您的控制器中更重要的一点是有一条评论“// POST:AdminHome/Edit/5”,当您点击“保存”时,您似乎是从“预订”视图发布的(提交) 按钮,您是否调试过使用开发人员工具进行的 xhr 请求?它是否会使用您期望的表单数据进入正确的控制器和操作? 是的,它从脚手架编辑页面转到正确的控制器和操作,即具有 Booking 作为参数的 Edit 方法。但是当我按下保存时,我不确定如何将 AttendingPeople 更改绑定到 Booking。在顶部的 Edit 方法中,我将 AttendingPeople 添加到 Booking,在我的视图 (Edit.cshtml) 中,我可以从 Model 中获取值。我尝试在 Edit 方法的参数中添加“ICollection AttendPeople”甚至“string[] AttendPeople”,但它们始终为空。 您的 AttendingPeople 在视图中的填充是否正确?您还检查过哪些 html 被渲染为 html 吗?您的参加者是否被添加为数组对象,例如编辑器字段的 id 是 AttendingPeople[0]、AttendingPeople[1] 等?这就是我要参考的内容-***.com/questions/19964553/… 上的投票答案 --- 请注意,您不需要在答案中将解决方案实现为编辑器/显示模板。还有其他方法。 【参考方案1】:

感谢 JARRRRG 在这里帮助我。 :)

为了解决这个问题,我需要确保我的命名完全相同。显然这就是它从视图中查找/绑定到控制器的方式。我还需要确保我使用了 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 - 如何首先使用 EF 代码更新关系表的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 MVC3 多对多关系和 EF4.1 模型优先检索数据?

在 EF 6 和 MVC 5 中使用 Code First 方法将新表添加到现有数据库

如何首先使用ef代码将表中的键用于另一个表中的两个不同列

MVC 模型如何使 byte[] 可以为空?

如何仅保存/更新父实体而不将其子实体保存在 asp.net mvc 的 EF6 中?

使用默认成员关系的 MVC3 实体框架