我正在学习实体框架,我需要一些解释。
假设我已经创建了一些多对多关系,因此我们有表Students
和Courses
,每种类型的实体可以有许多其他类型的实体。
接下来,我有一个gridview,我想在这里显示两列描述学生姓名和他所分配的所有课程的表格。出于此目的,在我Page_Load
的{{1}}事件中,我有以下代码:
WebForm
现在它有效,但请注意,实体框架并未真正分析查询,因为行:
protected void Page_Load(object sender, EventArgs e)
{
MyModel dbContext = new MyModel();
GridView1.DataSource = from student in dbContext.Students
.Include("Courses").ToList()
select new
{
Name = student.StudentName,
Courses = string.Join(",", student.Courses.Select(c => c.CourseName))
};
GridView1.DataBind();
}
使LINQ to Objects提供程序分析此查询。如果我不使用GridView1.DataSource = from student in dbContext.Students.Include("Courses").ToList()
方法,而是我想写:
ToList()
然后我得到var query = from student in dbContext.Students.Include("Courses")
select new { ... };
GridView1.DataSource = query.ToList();
GridView1.DataBind();
无法识别Join()
方法的例外情况。我可以忍受这一点,但如果查询是由EF的引擎分析的话,猜测应用程序会运行得更快,我是对的吗?
如果是这样,我如何重写代码,将字符串分配给我的匿名类型的Entity Framework
属性以获得相同的结果?
答案 0 :(得分:2)
关于为什么Join()
不起作用。
代码
var query = from student in dbContext.Students.Include("Courses") select new { ... };
返回IQueryable
。此时您的数据尚未实现(=没有调用数据库来获取实体)。这意味着当您稍后调用ToList()
(=实现您的实体)时,查询中包含的所有内容都将转换为SQL。 SQL对string.Join()
一无所知,这就是它抱怨的原因。你的第一个例子只是因为LinqToObjects是用C#执行的,而不是SQL(因此,它知道如何处理string.Join()
)
有关您可以和不能包含在查询中的内容的更多信息:
Supported and Unsupported LINQ Methods (LINQ to Entities)
CLR Method to Canonical Function Mapping
更新
虽然这不是问题的一部分,但值得一提的是,您可能需要为您的数据实施分页。您不太可能希望一次在一个数据网格中显示数百和数千个项目。搜索Take()
。
答案 1 :(得分:2)
到目前为止,您完成此方式的唯一真正问题是,如果您要应用过滤,则会在调用ToList
后应用,因此在记忆中完成。
我会将您的查询分为两部分。第一部分将从数据库中读取数据(并允许您包含where
子句),而第二部分将对象映射到格式。
protected void Page_Load(object sender, EventArgs e)
{
using (var dbContext = new MyModel())
{
var students = (from student in dbContext.Students
/*optional where clause*/
select new
{
Name = student.StudentName,
Courses = student.Courses.Select(c => c.CourseName)
}).ToList();
GridView1.DataSource = students.Select(s => new { s.Name, Courses = String.Join(",", s.Courses)}).ToList();
GridView1.DataBind();
}
}
值得一提的是,您可以使用Aggregate
完全在EF中重新创建它,但我认为这不是必要的。