通过外键关系访问第二个table值
Access second table value through foreign key relationship
我正在创建一个应用程序,以便使用 ASP、MVC 和 Entity Framework。我一直在关注 this 教程,更改数据模型以满足我的需要。
我已将所有用户数据显示在 table 内的页面上。在我的模型中,我有一个单独的 table 用于用户所属的教员。在包含用户详细信息的页面上,它当前显示的是教员 table 的主键。我想在它的位置显示教员姓名。我怎样才能做到这一点?
使用下面显示的代码,我希望能够使用以下代码行来显示教员姓名,但是由于变量教员为空,这显示了一个包含空字符串的单元格。
@Html.DisplayFor(modelItem => item.faculty.name)
如果我使用 PHP 我会这样做;
SELECT faculty_name
FROM faculties
WHERE user.school = faculties.id;
用户模型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Purely_Servers.Models
{
[Table("userTable")]
public class user
{
[Key]
public int id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public int house_number { get; set; }
public string street { get; set; }
public string city { get; set; }
public string postcode { get; set; }
public int authorised { get; set; }
public int school { get; set; }
public int archived { get; set; }
public virtual faculty faculty { get; set; }
}
}
师资模范
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Purely_Servers.Models
{
[Table("facultyTable")]
public class faculty
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string location { get; set; }
}
}
显示用户学校
当前显示的是教职工table记录主键对应的数值。
@model IEnumerable<Purely_Servers.Models.user>
@foreach (var item in Model){
<tr>
//other code
<td>
@Html.DisplayFor(modelItem => item.school)
</td>
</tr>
}
用户控制器
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using Purely_Servers.DAL;
using Purely_Servers.Models;
namespace Purely_Servers.Controllers
{
public class usersController : Controller
{
private serverContext db = new serverContext();
// GET: users
public ActionResult Index()
{
return View(db.Users.ToList());
}
// GET: users/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
user user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
// GET: users/Create
public ActionResult Create()
{
return View();
}
// POST: users/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,first_name,last_name,email,house_number,street,city,postcode,authorised,school,archived")] user user)
{
if (ModelState.IsValid)
{
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
// GET: users/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
user user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
// POST: users/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,first_name,last_name,email,house_number,street,city,postcode,authorised,school,archived")] user user)
{
if (ModelState.IsValid)
{
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
// GET: users/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
user user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
// POST: users/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
user user = db.Users.Find(id);
db.Users.Remove(user);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
非常感谢任何帮助。
Html.DisplayFor
使用 lamdba 表达式。您声明 modelItem
但随后在表达式中使用 item
。您的代码应为:
@Html.DisplayFor(modelItem => modelItem.faculty.name)
根据您的编辑:
更简单地说,您可以只使用 @item.faculty.name
。
仔细查看您发布的代码,您似乎没有正确维护 user
和 faculty
之间的关系。
在您的 user
中,您有一个 属性 int school {get;set;}
,您建议它代表用户所属设施的外键。这可能确实是真的,但您实际上并没有将这一事实通知 Entity Framework。实际上,school
属性 是不必要的。
在您的 Create 操作中,您接受 int school
作为参数(可能是从下拉列表派生的 int)。然后你继续将它作为一个值保存在数据库中,Entity Framework 很乐意这样做,却不知道这实际上代表了一种关系。
您可能打算在创建操作中执行的操作更像是:
if (ModelState.IsValid)
{
db.Users.Add(user);
// Find Faculty in the database and add the user to the faculty's collection.
var faculty = db.Faculty.Find(school);
faculty.users.add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
现在,school
参数是不必要的,因为它是 faculty.id
的副本
在您的 Details
操作中,您现在可以使用 Include()
将 faculty
与 user
一起发送,如下所示:
user user = db.Users.Include(u => u.faculty).SingleOrDefault(u => u.id == id);
(请注意,添加 Include
需要使用 SingleOrDefault
而不是 Find
。如果启用延迟加载,则 Include
并非完全必要,但 效率更高。)
有了这个,item.faculty
不再是null
,你可以输出item.faculty.id
,item.faculty.name
,等等
这也是 Loading related entities 上 MSDN 文章的 link。
我正在创建一个应用程序,以便使用 ASP、MVC 和 Entity Framework。我一直在关注 this 教程,更改数据模型以满足我的需要。
我已将所有用户数据显示在 table 内的页面上。在我的模型中,我有一个单独的 table 用于用户所属的教员。在包含用户详细信息的页面上,它当前显示的是教员 table 的主键。我想在它的位置显示教员姓名。我怎样才能做到这一点?
使用下面显示的代码,我希望能够使用以下代码行来显示教员姓名,但是由于变量教员为空,这显示了一个包含空字符串的单元格。
@Html.DisplayFor(modelItem => item.faculty.name)
如果我使用 PHP 我会这样做;
SELECT faculty_name
FROM faculties
WHERE user.school = faculties.id;
用户模型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Purely_Servers.Models
{
[Table("userTable")]
public class user
{
[Key]
public int id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public int house_number { get; set; }
public string street { get; set; }
public string city { get; set; }
public string postcode { get; set; }
public int authorised { get; set; }
public int school { get; set; }
public int archived { get; set; }
public virtual faculty faculty { get; set; }
}
}
师资模范
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Purely_Servers.Models
{
[Table("facultyTable")]
public class faculty
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string location { get; set; }
}
}
显示用户学校
当前显示的是教职工table记录主键对应的数值。
@model IEnumerable<Purely_Servers.Models.user>
@foreach (var item in Model){
<tr>
//other code
<td>
@Html.DisplayFor(modelItem => item.school)
</td>
</tr>
}
用户控制器
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using Purely_Servers.DAL;
using Purely_Servers.Models;
namespace Purely_Servers.Controllers
{
public class usersController : Controller
{
private serverContext db = new serverContext();
// GET: users
public ActionResult Index()
{
return View(db.Users.ToList());
}
// GET: users/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
user user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
// GET: users/Create
public ActionResult Create()
{
return View();
}
// POST: users/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,first_name,last_name,email,house_number,street,city,postcode,authorised,school,archived")] user user)
{
if (ModelState.IsValid)
{
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
// GET: users/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
user user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
// POST: users/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,first_name,last_name,email,house_number,street,city,postcode,authorised,school,archived")] user user)
{
if (ModelState.IsValid)
{
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
// GET: users/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
user user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
// POST: users/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
user user = db.Users.Find(id);
db.Users.Remove(user);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
非常感谢任何帮助。
Html.DisplayFor
使用 lamdba 表达式。您声明 modelItem
但随后在表达式中使用 item
。您的代码应为:
@Html.DisplayFor(modelItem => modelItem.faculty.name)
根据您的编辑:
更简单地说,您可以只使用 @item.faculty.name
。
仔细查看您发布的代码,您似乎没有正确维护 user
和 faculty
之间的关系。
在您的 user
中,您有一个 属性 int school {get;set;}
,您建议它代表用户所属设施的外键。这可能确实是真的,但您实际上并没有将这一事实通知 Entity Framework。实际上,school
属性 是不必要的。
在您的 Create 操作中,您接受 int school
作为参数(可能是从下拉列表派生的 int)。然后你继续将它作为一个值保存在数据库中,Entity Framework 很乐意这样做,却不知道这实际上代表了一种关系。
您可能打算在创建操作中执行的操作更像是:
if (ModelState.IsValid)
{
db.Users.Add(user);
// Find Faculty in the database and add the user to the faculty's collection.
var faculty = db.Faculty.Find(school);
faculty.users.add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
现在,school
参数是不必要的,因为它是 faculty.id
在您的 Details
操作中,您现在可以使用 Include()
将 faculty
与 user
一起发送,如下所示:
user user = db.Users.Include(u => u.faculty).SingleOrDefault(u => u.id == id);
(请注意,添加 Include
需要使用 SingleOrDefault
而不是 Find
。如果启用延迟加载,则 Include
并非完全必要,但 效率更高。)
有了这个,item.faculty
不再是null
,你可以输出item.faculty.id
,item.faculty.name
,等等
这也是 Loading related entities 上 MSDN 文章的 link。