• Entity Framework学习笔记(四)----Linq查询(1)


    请注明转载地址:http://www.cnblogs.com/arhat

    从本章开始,老魏就介绍一下Entity Framework使用Linq来查询数据,也就是Linq To Entity。其实在Entity Framework中提供了3中查询方式,除了使用Linq还有Lambda表达式,EQL语句,其中EQL是用于复杂的查询,当Linq无法胜任的时候就要使用了EQL了,当然也可以使用存储过程。废话不多说,开始本章的内容。

    在本章中查询的依然是Student和Clazz两张表,主要涉及到是单表查询和一个关联查询,对于多对多查询将在下一章讲解。

    Demo1:查询一下全部学生的信息。

    原生SQL:

    select * from Student

    Linq:

    DAL.SchoolContext context = new DAL.SchoolContext();
    
    var query = from student in context.Student
    
    select student;
    
    foreach (var student in query)
    
    {
    
    Console.WriteLine(student.SId + "----" + student.SName + "----" + student.SAge + "----" + student.SMail);
    
    }

    翻译SQL:

    SELECT 
    
        [Extent1].[SId] AS [SId], 
    
        [Extent1].[SName] AS [SName], 
    
        [Extent1].[SAge] AS [SAge], 
    
        [Extent1].[SMail] AS [SMail], 
    
        [Extent1].[CId] AS [CId]
    
        FROM [dbo].[Student] AS [Extent1]

    结果:

    wps_clip_image-12154

    大家看到这个Linq翻译的SQL语句还是非常不错的。并没有额外的开支。

    Demo2:查询一下全部学生的信息,并显示学生所在的班级信息。

    原生SQL:

    select * from Student as a inner join Clazz as b on a.CId= b.CId

    Linq:

    DAL.SchoolContext context = new DAL.SchoolContext();
    
    var query = from student in context.Student
    
    select student;
    
    foreach (var student in query)
    
     {
    
    Console.WriteLine(student.SId + "----" + student.SName + "----" + student.SAge + "----" + student.SMail+"----班级信息:"+student.Clazz.CId+"----"+student.Clazz.CName);
    
    }

    翻译SQL:这个老魏就不贴出来了,太长了,大家可以看看

    wps_clip_image-5241

    从图上可以看出,这个Linq执行的时候是先把学生全部查询出来,然后在根据Student.CId字段分别取得到Clazz信息,如果我们的信息有100000条数据的话,可想而知了。虽然牺牲了性能,但却换来了编程上的方便。如果大家思考一下老魏的这程序,会发现项目中没有这么干的,如果数据多的请情况下肯定要使用分页的,如果使用分页的话,那么产生的SQL查询次数肯定要比全部的少很多,的确如此,但是还是多了。其实这也没有办法,在所有的ORM框架中使用懒加载的时候都是如此,牺牲效率。

    在这里呢,Entity Framework是默认启用懒加载机制的,所谓的懒加载老魏在NHibernate中已经讲解过了,其实就是在使用的时候在向SQL发送查询指令。这里我们通过Student的Clazz导航属性来得到班级的信息。当然如果我们不需班级信息的话,那么就不会向SQL发送指令了。

    结果:

    wps_clip_image-25654

    此时呢,我们在换一种写法,不使用懒加载,而是通过Linq的join语句来试试看看。

    Linq:

    DAL.SchoolContext context = new DAL.SchoolContext();
    
    var query = from student in context.Student
    
    join clazz in context.Clazz
    
    on student.CId equals clazz.CId
    
    select new
    
     {
    
          SName =student.SName,
    
          CName = clazz.CName
    
    };
    
    foreach (var record in query)
    {
    
    Console.WriteLine(record.SName + "----" + record.CName);
    
     }

    翻译SQL:

    SELECT
    
    [Extent2].[CId] AS [CId], 
    
    [Extent1].[SName] AS [SName], 
    
    [Extent2].[CName] AS [CName]
    
    FROM [dbo].[Student] AS [Extent1]
    
    INNER JOIN [dbo].[Clazz] AS [Extent2] ON [Extent1].[CId] = [Extent2].[CId]

    这个时候,我们发现了,这个Linq生成的SQL语句还真是我们想要的语句,直接把我们想要的东西通过inner join来查询出来了,可是随之的问题有出现了,为什么呢?如果我们要分层的开发项目,这段代码应该是在DAL层中的,但是此时我们用了匿名对象来保存我们的查询结果,而匿名对象是不能跨域访问的,这该怎么办呢?这里呢老魏也没想到好的方法,但是提供两个参考

    1,使用扩展防方法给IEnumable<T>扩展一个方法,优点复杂老魏不喜欢

    2,使用.net4.0的dynamic关键字,虽然可以实现,但是没有智能提示,不过勉强接受。

    static void Main(string[] args)
    {
    
    var query = Test();
    
    foreach (dynamic d in query)
    
      {
    
    Console.WriteLine(d.SName + "----" + d.CName);
    
      }
    
    }
    
    public static dynamic Test()
    {
    
    DAL.SchoolContext context = new DAL.SchoolContext();
    
    var query = from student in context.Student
    
    join clazz in context.Clazz
    
    on student.CId equals clazz.CId
    
    select new
     {
    
         SName = student.SName,
    
         CName = clazz.CName
    };
    
    return query as dynamic;
    
    }

    谁有好的方法可以共享一下,老魏这里实在是想不到一个好的方法了。好了,不在这个问题上过多的纠缠了。

    可能看到这里我们有会忽然间想到,如果我们不查询部分字段那又是什么情况呢?

    Linq:

    DAL.SchoolContext context = new DAL.SchoolContext();
    
    var query = from student in context.Student
    
    join clazz in context.Clazz
    
    on student.CId equals clazz.CId
    
    into Rows
    
    from row in Rows
    
    select row;
    
    foreach (var row in query)
     {
    
    Console.WriteLine(row.CName);
    
    }

    当我们写到row.的时候,会发现row这个对象中只有CId,CName和一个奇怪的Students对象。这是怎么回事啊。我们通过这条Linq语句生成的SQL语句可以看出端倪。

    翻译SQL:

    SELECT
    
    [Extent2].[CId] AS [CId], 
    
    [Extent2].[CName] AS [CName]
    
    FROM [dbo].[Student] AS [Extent1]
    
    INNER JOIN [dbo].[Clazz] AS [Extent2] ON [Extent1].[CId] = [Extent2].[CId]

    wps_clip_image-30143

    大家从翻译的SQL中可以看到最终查询的结果是是吧Clazz的字段全部查询出来了,查询结果如下:

    wps_clip_image-2067

    每一个课程都有一个Student对象,那么当然在Clazz中有一个Students对象。只有当我们查询Student对象的时候,才会向SQL依次的发送指令。其实还是懒加载,。看到这里我们是不是相到既然这样我们可以关闭懒加载啊,是的,可以的没有任何的问题,我们在上面的代码中我们加入一句话。

    DAL.SchoolContext context = new DAL.SchoolContext();
    
    //取消懒加载
    
     context.Configuration.LazyLoadingEnabled = false;
    
    var query = from student in context.Student
    
    join clazz in context.Clazz
    
    on student.CId equals clazz.CId
    
    into Rows
    
    from row in Rows
    
    select row;
    
    foreach (var row in query)
    
    {
    
    Console.WriteLine(row.CName+",次班级的人数:"+row.Students.Count);
    
     }

    运行结果:

    wps_clip_image-24764

    发现人数打印出来是0,因为我们取消了懒加载,所以在使用到了Student的时候不会向SQL发送指令,就不会查询人数了,但是从上图中其实我们看出来总的记录加起来还是人数哦!

    本章就先到这里吧,虽然本章只涉及到了2个查询,但还是有收货的,值得在我们学习Entity Framework的时候多深入的思考一下。

  • 相关阅读:
    regulation
    Java第三方类库
    python整个小服务器
    VsFTP出现500 OOPS: cannot change directory的解决办法
    Got error 28 from storage engine
    linux下ftp操作
    linux安装JDK
    Apache + Tomcat + Linux 集群和均衡负载 (Session 同步复制) 配置实
    怎么样才能使得PL/SQL Developer不显示系统表?
    sudo 用法
  • 原文地址:https://www.cnblogs.com/arhat/p/3650516.html
Copyright © 2020-2023  润新知