在一个数据库操作中使用结构[a]1:n[B]n:1[C]1:n[D]进行查询
本文关键字:查询 结构 一个 数据库 操作 | 更新日期: 2023-09-27 17:58:10
我正在现有SQL Server数据库上使用实体框架作为ORM构建一个ASP.NET MVC 4应用程序这是模型优先,而不是代码优先我是LINQ to Entity的新手。最近我遇到了一些问题,我很难在网上找到任何帮助。我现在已经解决了两次。这是我的故事。
我有一个视图,需要显示模块列表(如在课堂教学中)。每个模块属于一个单元,但每个单元可以有多个模块。每个模块可以有多个讲师,每个讲师可以教授多个模块。存在一个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、讲师。我的问题是,我最难让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中,我得到了除Instructors之外的所有东西,然后分别获得了Instructorss,并将它们循环插入集合中。
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个模块。
然而,我认为一定有一种方法可以在一个数据库调用中实现这一点。这是我的新解决方案。我仍然循环将讲师插入Modules对象的讲师集合,但我获得了所有讲师和其他所有内容。
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上的这种特殊情况,似乎没有答案,我正在努力解决这个问题。这个问题包括我所有的尝试,如果我没有得到回应,我将用我自己的最终解决方案来回答。
我认为https://stackoverflow.com/a/7966436/596146更多的是你想要的。我以前没有使用过实体框架(只有Fluent NHibernate),但我认为Module
应该有一个ICollection<Instructor>
而不是ICollection<ModuleInstructor>
,然后你告诉EF关于关联表的信息。