我正在使用 Entity Framework 作为我的 ORM 在现有 SQL Server 数据库之上构建一个 ASP.NET MVC 4 应用程序。这是模型优先,而不是代码优先。我对 LINQ to Entities 相当陌生。最近我遇到了很多问题,我很难在网上找到任何帮助。我现在已经解决了两次。这是我的故事。
我有一个需要显示模块列表的视图(如课堂教学)。每个 Module 属于一个 Unit,但每个 Unit 可以有多个 Module。每个模块可以有多个讲师,每个讲师可以教授多个模块。有一个 ModuleInstructor 表可以加入该关系。
Unit Module ModuleInstructor Instructor
======== 1:N ======== N:1 ================== 1:N ============
UnitID ModuleID ModuleInsturctorID InstructorID
UnitName UnitID ModuleID InstructorName
StartDate InsturctorID
EntityFramework 有这些对象[为了简洁而修剪了不必要的属性]:
public partial class Unit
{
public int UnitID { get; set; }
public string UnitName { get; set; }
public virtual ICollection<Module> Module { get; set; }
}
public partial class Module
{
public Module()
{
this.ModuleInstructor = new HashSet<ModuleInstructor>();
this.Record = new HashSet<Record>();
}
public int ModuleID { get; set; }
public Nullable<int> UnitID { get; set; }
public Nullable<System.DateTime> ModuleDate { get; set; }
public virtual Unit Unit { get; set; }
public virtual ICollection<ModuleInstructor> ModuleInstructor { get; set; }
}
public partial class ModuleInstructor
{
public int ModuleInstructorID { get; set; }
public Nullable<int> InstructorID { get; set; }
public Nullable<int> ModuleID { get; set; }
public Instructor Instructor { get; set; }
public virtual Module Module { get; set; }
}
public partial class Instructor
{
public Instructor()
{
this.ModuleInstructor = new HashSet<ModuleInstructor>();
}
public int InstructorID { get; set; }
public string InstructorName { get; set; }
public virtual ICollection<ModuleInstructor> ModuleInstructor { get; set; }
}
无论如何,我想在逗号分隔的列表中显示:UnitName、ModuleDate、Instructor(s)。我的问题是我最难让 Linq 获得 Instructors,我所能检索到的只是 ModuleInstructors,它没有加载任何 Instructor 信息。
private Entities db = new Entities();
public ActionResult Index(int p = 1)
{
int pageSize = 20;
var modules = db.Modules
.Include(m => m.Unit)
.Include(m => m.ModuleInstructor)
.Include(m => m.ModuleInstructor.Instructor) //Doesn't work
.OrderByDescending(m => m.ModuleStartDate)
.Skip(pageSize * (p - 1))
.Take(pageSize);
return View(modules);
}
我的第一个解决方案是修改 Module 类以添加另一个集合:
public partial class Module
{
public Module()
{
this.ModuleInstructor = new HashSet<ModuleInstructor>();
this.Record = new HashSet<Record>();
}
public int ModuleID { get; set; }
public Nullable<int> UnitID { get; set; }
public Nullable<System.DateTime> ModuleDate { get; set; }
public virtual Unit Unit { get; set; }
public virtual ICollection<Instructor> Instructor { get; set; } //Added
public virtual ICollection<ModuleInstructor> ModuleInstructor { get; set; }
}
在 ModuleController 中,我得到了除 Instructors 之外的所有内容,然后是 Instructors,它们分别并通过将它们插入集合中进行循环。
private Entities db = new Entities();
public ActionResult Index(int p = 1)
{
int pageSize = 20;
var modules = db.Modules
.Include(m => m.Unit)
.Include(m => m.ModuleInstructor)
.OrderByDescending(m => m.ModuleStartDate)
.Skip(pageSize * (p - 1))
.Take(pageSize);
var instructors = db.Instructors.ToList();
foreach (var m in modules)
{
m.Instructor = new List<Instructor>();
foreach (var mi in m.ModuleInstructor)
{
m.Instructor.Add(instructors
.Where(i => i.InstructorID == mi.InstructorID).SingleOrDefault());
}
}
return View(modules);
}
根据 LinqPad,这需要两条 SQL 语句。还不错。服务器上的压力也不大,因为我没有很多讲师,而且每次只有 20 个模块显示。
但是,我认为必须有一种方法可以在一个数据库调用中做到这一点。这是我的新解决方案。我仍然循环将 Instructors 插入到 Modules 对象的 Instructor 集合中,但我得到了所有 Instructors 以及其他所有内容。
public ActionResult Index(int p = 1)
{
int pageSize = 20;
var modules = db.Modules
.Include(m => m.Unit)
.Include(m => m.ModuleInstructor)
.Include(m => m.ModuleInstructor.Select(mi => mi.Instructor)) //New 'trick'
.OrderByDescending(m => m.ModuleStartDate)
.Skip(pageSize * (p - 1))
.Take(pageSize);
foreach (var m in modules)
{
m.Instructor = new List<Instructor>();
foreach (var mi in m.ModuleInstructor)
{
//Adds from the ModuleInstructor instead of pairing from another list
m.Instructor.Add(mi.Instructor);
}
}
return View(modules);
}
根据 LinqPad 的说法,它只需要 SQL 语句,它的执行速度比第一种方法稍快。
老实说,我很难准确地想象它是如何工作的以及为什么,但确实如此。我很高兴我坚持了这个问题,多次回到它,直到我“恰到好处”。
我的一个问题是:这是最好的方法还是有更好的方法?
澄清:我无法更改我的数据库表,并且对更改我的课程不感兴趣。我在问是否有更好的方法来使用数据结构进行此操作。StackOverflow 上的这种特殊情况似乎没有答案,我正在尝试继续。这个问题包括我所有的尝试,如果我没有收到回复,我将用我自己的最终解决方案来回答。