我正在使用Entity Framework构建一个ASP.NET MVC 4应用程序作为我的ORM在现有SQL Server数据库之上。 这是模型优先,而不是代码优先。我对LINQ to Entities相当新。最近我碰到了一些给我带来很多问题的东西,我在网上寻找任何帮助都很困难。我现在已经解决了两次。这是我的故事。
我认为需要显示模块列表(如课堂教学)。每个模块属于一个单元,但每个单元可以有许多模块。每个模块可以有多个教师,每个教师可以教授许多模块。有一个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。我的问题是我最难让Linq获得教师,我只能检索到没有加载任何教师信息的ModuleInstructors。
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中,除了教师之外,我得到了所有内容,然后是教师,并通过将它们插入到集合中来循环播放。
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集合中来循环,但是我得到了所有其他教师。
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上的这种特殊情况似乎没有答案,我试图在这里继续。这个问题包括我的所有尝试,如果我没有收到回复,我会用自己的最终解决方案回答。
答案 0 :(得分:1)
我认为https://stackoverflow.com/a/7966436/596146更符合您的要求。我之前没有使用过Entity Framework(仅Fluent NHibernate),但我认为Module
应该有ICollection<Instructor>
而不是ICollection<ModuleInstructor>
,然后告诉EF关于关联表