按实体框架分析查询

时间:2016-04-02 17:06:27

标签: c# sql asp.net entity-framework linq

我正在学习实体框架,我需要一些解释。

假设我已经创建了一些多对多关系,因此我们有表StudentsCourses,每种类型的实体可以有许多其他类型的实体。

接下来,我有一个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属性以获得相同的结果?

2 个答案:

答案 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中重新创建它,但我认为这不是必要的。