如何在MVC 5中将两个或多个表链接在一起

时间:2016-05-31 10:16:37

标签: asp.net-mvc-5

Sup SO。

我在数据库和网络的其他技术中学习MVC 5和ASP.NET,我正在该环境中进行示例项目。到目前为止,我已经设法创建了一个成功显示三个表的网站,您可以搜索至少其中一个表,并创建新条目,编辑和删除所有三个表的现有条目。

我现在需要做的就是将这三者联系起来,就像我在SQL中使用INNER JOIN一样。

因此,这些表格是员工,技能熟练程度和技能描述。

  • 员工都拥有一套他们熟悉的技能,并且熟练掌握每一项技能。他们还有一个员工ID。

  • 技能熟练度表包含哪个员工知道什么技能和什么级别的数据,但只保留员工ID和技能ID以匹配它们,以及表示熟练程度的int。

  • 技能描述表包含每种技能的技能ID,以及人类可读的名称,如C ++,HTML等。

在这种情况下,所需的效果是单个表,每个条目都有一个雇员的名字(取自Employees表),技能名称(取自技能描述表)和熟练程度该员工和技能的级别(取自技能熟练程度表)。

到目前为止,我在这个主题上找到的内容要么是针对另一个版本的MVC,要么是以一种将数据作为纯文本返回的方式显示出来的,而我希望它在列表中返回,就像我已经在做如下所示。

EmployeesController:

using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using SDS.Models;
using System;

namespace SDS.Controllers
{
    public class EmployeesController : Controller
    {
        private SDSDbContext db = new SDSDbContext();

        // GET: Employees
        public ActionResult Index(string searchString)
        {
            var employeesQuery = from e in db.Employees select e;

            if (!String.IsNullOrEmpty(searchString))
            {
                employeesQuery = employeesQuery.Where(x => x.FirstName.Contains(searchString)
                                                    || x.MiddleName.Contains(searchString)
                                                    || x.LastName.Contains(searchString)
                                                    || x.EmployeeAID.ToString().Contains(searchString)
                                                    || x.StaffNo.ToString().Contains(searchString)
                                                    || x.JobTitle.Contains(searchString));
            }

            return View(employeesQuery.ToList());
        }

        // GET: Employees/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Employee employee = db.Employees.Find(id);
            if (employee == null)
            {
                return HttpNotFound();
            }
            return View(employee);
        }

        // GET: Employees/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: Employees/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "EmployeeID,EmployeeAID,FirstName,MiddleName,LastName,StaffNo,JobTitle")] Employee employee)
        {
            if (ModelState.IsValid)
            {
                db.Employees.Add(employee);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(employee);
        }

        // GET: Employees/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Employee employee = db.Employees.Find(id);
            if (employee == null)
            {
                return HttpNotFound();
            }
            return View(employee);
        }

        // POST: Employees/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "EmployeeID,EmployeeAID,FirstName,MiddleName,LastName,StaffNo,JobTitle")] Employee employee)
        {
            if (ModelState.IsValid)
            {
                db.Entry(employee).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            } 
           return View(employee);
        }

        // GET: Employees/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Employee employee = db.Employees.Find(id);
            if (employee == null)
            {
                return HttpNotFound();
            }
            return View(employee);
        }

        // POST: Employees/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            Employee employee = db.Employees.Find(id);
            db.Employees.Remove(employee);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
               db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

员工模型:

namespace SDS.Models
{
    public class Employee
    {
        public int EmployeeID { get; set; }

        public int EmployeeAID { get; set; }

        public string FirstName { get; set; }

        public string MiddleName { get; set; }

        public string LastName { get; set; }

        public int StaffNo { get; set; }

        public string JobTitle { get; set; }

        public SkillDescription skillDescription { get; set; }

        public SkillProficiency skillProficiency { get; set; }
    }
}

SkillDescriptions控制器:

using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using SDS.Models;

namespace SDS.Controllers
{
    public class SkillDescriptionsController : Controller
    {
        private SDSDbContext db = new SDSDbContext();

        // GET: SkillDescriptions
        public ActionResult Index()
        {
            return View(db.SkillDescriptions.ToList());
        }

        // GET: SkillDescriptions/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            SkillDescription skillDescription = db.SkillDescriptions.Find(id);
            if (skillDescription == null)
            {
                return HttpNotFound();
            }
            return View(skillDescription);
        }

        // GET: SkillDescriptions/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: SkillDescriptions/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "ID,Description")] SkillDescription skillDescription)
        {
            if (ModelState.IsValid)
            {
                db.SkillDescriptions.Add(skillDescription);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(skillDescription);
        }

        // GET: SkillDescriptions/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            SkillDescription skillDescription = db.SkillDescriptions.Find(id);
            if (skillDescription == null)
            {
                return HttpNotFound();
            }
            return View(skillDescription);
        }

        // POST: SkillDescriptions/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "ID,Description")] SkillDescription skillDescription)
        {
            if (ModelState.IsValid)
            {
                db.Entry(skillDescription).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(skillDescription);
        }

        // GET: SkillDescriptions/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            SkillDescription skillDescription = db.SkillDescriptions.Find(id);
            if (skillDescription == null)
            {
                return HttpNotFound();
            }
            return View(skillDescription);
        }

        // POST: SkillDescriptions/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            SkillDescription skillDescription = db.SkillDescriptions.Find(id);
            db.SkillDescriptions.Remove(skillDescription);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

SkillDescription模型:

namespace SDS.Models
{
    public class SkillDescription
    {
        public int ID { get; set; }

        public string Description { get; set; }
    }
}

SkillProficiencies控制器:

using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using SDS.Models;

namespace SDS.Controllers
{
    public class SkillProficienciesController : Controller
    {
        private SDSDbContext db = new SDSDbContext();

        // GET: SkillProficiencies
        public ActionResult Index()
        {
            return View(db.SkillProficiencies.ToList());
        }

        // GET: SkillProficiencies/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            SkillProficiency skillProficiency = db.SkillProficiencies.Find(id);
            if (skillProficiency == null)
            {
                return HttpNotFound();
            }
            return View(skillProficiency);
        }

        // GET: SkillProficiencies/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: SkillProficiencies/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "ID,EmployeeAID,SkillID,Proficiency1To5")] SkillProficiency skillProficiency)
        {
            if (ModelState.IsValid)
            {
                db.SkillProficiencies.Add(skillProficiency);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(skillProficiency);
        }

        // GET: SkillProficiencies/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            SkillProficiency skillProficiency = db.SkillProficiencies.Find(id);
            if (skillProficiency == null)
            {
                return HttpNotFound();
            }
            return View(skillProficiency);
        }

        // POST: SkillProficiencies/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "ID,EmployeeAID,SkillID,Proficiency1To5")] SkillProficiency skillProficiency)
        {
            if (ModelState.IsValid)
            {
                db.Entry(skillProficiency).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(skillProficiency);
        }

        // GET: SkillProficiencies/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            SkillProficiency skillProficiency = db.SkillProficiencies.Find(id);
            if (skillProficiency == null)
            {
                return HttpNotFound();
            }
            return View(skillProficiency);
        }

        // POST: SkillProficiencies/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            SkillProficiency skillProficiency = db.SkillProficiencies.Find(id);
            db.SkillProficiencies.Remove(skillProficiency);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

SkillProficiency Model:

namespace SDS.Models
{
    public class SkillProficiency
    {
        public int ID { get; set; }

        public int EmployeeAID { get; set; }

        public int SkillID { get; set; }

        public int Proficiency1To5 { get; set; }
    }
}

只是为了让您了解数据现在的显示方式,这里是SkillsProficiency表的Index.cshtml:

@model IEnumerable<SDS.Models.SkillProficiency>

@{
    ViewBag.Title = "Skill Proficiencies";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.EmployeeAID)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.SkillID)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Proficiency1To5)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.EmployeeAID)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.SkillID)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Proficiency1To5)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
            @Html.ActionLink("Details", "Details", new { id=item.ID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.ID })
        </td>
    </tr>
}

</table>

理想情况下,我希望在链接表格时保持页面的当前列表外观。这是技能熟练表现在的样子:

Skills Proficiencies Table

1 个答案:

答案 0 :(得分:1)

您的问题是信息过载。通常情况下,用户不会发布足够的内容,但是你却以相反的方式摆动并发布了超过必要的内容。这归结为您的实体类。我鼓励您花一些时间熟悉Entity Framework,因为这几乎是101件事。

也就是说,Entity Framework需要知道那些外键属性实际上适用于某个实体类。它不是无所不知的。此外,您的数据库结构中存在一些逻辑错误。你在这里拥有的是带有效载荷的M2M。员工有很多技能,技能有很多员工,但两者之间的关系需要额外的有效负载得分。

public class Employee
{
    public int Id { get; set; }

    ...

    public virtual ICollection<EmployeeSkill> Skills { get; set; }
}

public class Skill
{
    public int Id { get; set; }

    public string Description { get; set; }

    public virtual ICollection<EmployeeSkill> Employees { get; set; }
}

public class EmployeeSkill
{
    public int Id { get; set; }

    [ForeignKey("Employee")]
    public int EmployeeId { get; set; }
    public virtual Employee Employee { get; set; }

    [ForeignKey("Skill")]
    public int SkillId { get; set; }
    public virtual Skill Skill { get; set; }

    public int Proficiency1To5 { get; set; }
}

此处EmployeeSkill代表M2M关系的联接表。传统上,您直接引用相关实体并让Entity Framework隐式处理连接表,但由于涉及有效负载(熟练程度),您需要手动构建该关系。有了这些,您就可以执行以下操作:

var employee = db.Employees.Include("Skills.Skill").SingleOrDefault(m => m.Id == id);

然后,您可以获得所需的所有信息:

foreach (var skill in employee.Skills)
{
    // Skill Description = skill.Skill.Description
    // Skill Proficiency = skill.Proficiency1to5    
}