(.NET进阶二)Linq查询语句与查询方法

目录

一、Linq基础

二、LINQ查询方法

三、LINQ查询时机与查询形式

四、 LINQ查询子句

五、LINQ高级查询


一、Linq基础

1.LINQ能解决什么问题?

a.面向对象编程语言与数据访问方法长期分离,以嵌入式的方式开发。(嵌入的SQL语句没有任何提示,易出错)如

string sql = “select * from Student where StudentId = ”+studentId;

b.编程语言中的数据类型和数据库中的数据类型形成两套体系,如C#中的string在SQL中有NVarchar/Varchar/Char表示

c.SQL和XML都有各自的查询语言,而对象没有自己的查询语言,比如要从List<T>集合/数组中找到符合要求的元素,非常困难

 

 2.什么是LINQ

  • LINQ(Language Integrated Query,语言集成查询)
    1. 是微软公司提供的一项新技术,能欧冠将查询功能直接引入到C#、VB.NET等编程语言中
    2. 查询操作可以通过编程语言自身来表示,而不是嵌入字符串SQL语句
  • LINQ主要包含以下三部分
    1. LINQ to Object是主要负责对象的查询
    2. LINQ to XML主要负责XML的查询
    3. LINQ to ADO.NET主要负责数据库的查询(重点)
      1. LINQ to SQL(目前已不在使用)
      2. LINQ to DataSet
      3. LINQ to Entities(重点学习)
  • LINQ所在命名空间
    1. System.Linq;该命名空间已经由系统自动引入
    2. 因此微软默认建议多使用Linq技术查询

 

LINQ在数组中的操作

//不使用LINQ查询数组
static void Main(string[] args)//查询数组中的奇数
{
    int[] nums = {1,3,5,6,2,4,15,21};
    List<int> list = new Lint<int>();
    foreach(int item in nums)
    {
        if(item%2 != 0)
            list.Add(item);
    }
    list.Sort();
    list.Reverse();
    foreach(int item in list)
    {
        //输出list集合
    }
}
//使用LINQ查询数组
static void Main(string[] args)//查询数组中的奇数
{
    int[] nums = {1,3,5,6,2,4,15,21};
    //List<int> list = new Lint<int>();
    //foreach(int item in nums)
    //{
    //    if(item%2 != 0)
    //        list.Add(item);
    //}
    //list.Sort();
    //list.Reverse();

    //LINQ查询
    var list = from num in nums 
                where num%2!=0 
                orderby num descending 
                select num;
    foreach(int item in list)
    {
        //输出list集合
    }
}

二、LINQ查询方法

  1. 获取数据:扩展方法Select()
    1. Select()是一个泛型扩展方法
    2. Select()方法使用时要求传递一个委托实例(委托实例就是一个方法)
    3. Select()方法的应用
      static void Main(string[] args)
      {
          int[] nums = {1,4,2,7,5,10,23};
          var list = nums.Select(item => item*item);
          foreach(int i in list)
          {
              //输出list集合,结果为对应元素的平方
          }
      }
      
      1.Select()方法中是Lambda表达式
      2.返回结果是一个迭代器(Iterator)

      提示:数组、泛型集合都可以使用扩展方法Select()

  2. 筛选数据:Where()方法
    1. Where()方法是一个扩展类型方法
    2. Where()方法使用时需要传递一个委托实例,但该实例是一个判断条件,因此返回的类型必须是bool类型
      //找寻数组中偶数,并输出其平方
      static void Main(string[] args)
      {
          int[] nums = {1,4,2,7,9,12,13,20};
          var list = nums
                  .Where(item => item%2 == 0)
                  .Select(i => i*i);
      
          //var list = nums.Where(item => item*item).Select(i => i*i);//链式编程的两种表达方式
          foreach(int i in list)
          {
              //输出list集合
          }
      }
      
  3. 排序数据:OrderBy()
    1. OrderBy()是一个扩展方法
    2. OrderBy()里面的参数要求传递一个排序的字段,默认采用升序排列
    3. 如果使用降序,使用OrderByDescending方法
      //升序输出数组中偶数的平方
      static void Main(string[] args)
      {
          int nums = {1,4,2,6,9,14,19};
          var list = nums
                  .Where(item => item%2 == 0)
                  .Select(item => item*item)
                  .OrderBy(item => item);
          foreach(int i in list)
          {
              //输出list集合
          }
      }
      //按照姓氏降序输出名字为两个字的姓名
      static void Main(string[] args)
      {
          int[] nums = {"张三","王明林","李世桥","那英","成龙","张丽"};
          var list = nums
                  .Where(item => item.Length == 2)
                  .Select(item => item)
                  .OrderByDescending(item => item.Substring(0,1));
          foreach(string i in list)
          {
               //输出list集合
          }
      }

       

  4. 分组数据:GroupBy()方法

    1. GroupBy()是扩展方法

    2. GroupBy()里面的参数要求传递一个分组字段

      //分组显示姓名
      static void Main(string[] args)
      {
          string[] nums = {"张勇","王琦","成龙","巩俐","马冬梅","张弛","杜宇"};
          var list = nums
                  .Where(item => item.Length == 2)
                  .Select(item => item)
                  .GroupBy(item => item.Substring(0,1));
          foreach(var groupItem in list)
          {
              Console.WriteLine("分组字段{0}",groupItem.Key);
              foreach(var item in groupItem )
              {
                  //分组输出集合
              }
          }
      }

       

三、LINQ查询时机与查询形式

  1. LINQ查询时机
    1. 查询步骤:获取数据源、定义查询、执行查询
    2. 结论:定义查询后,查询并未立即执行,而是在遍历时真正执行查询,称为延迟执行(deferred  execution)
  2. 使用"聚合扩展方法"返回单一结果,强制查询立即执行:如Count()
    static void Main(string[] args)
    {
        int[] nums = {1,5,2,7,13,2,9,21};
        var list = nums
                .Where(item => item%2 == 0)
                .Select(item => item*item)
                .OrderBy(item => item)
                .Count();//语句将立即执行查询
    }

     

  3. LINQ查询两种形式

    1. Method Syntax,查询方法方式

      1. 主要利用System.Linq.Enumerable类中定义的扩展方法和Lambda表达式方式进行查询

    2. Query Syntax,查询语句方式

      1. 一种更接近SQL语法的查询方式,可读性更好

      2. 查询语句最后还是要被翻译成查询方法

        //查询语句
        var list = from num in nums 
                where num%2 != 0 
                orderby num descending 
                select num;
        
        //查询方法
        var list = nums
                .Where(item => item%2 != 0)
                .Select(item => item)
                .OrderByDescending(item => item);

        两种查询的执行效果完全一样

    3. 两种形式的比较

      1. CLR本身并不理解查询语句,只理解查询方法

      2. 编译器负责在编译时将查询语句翻译为查询方法

      3. 大部分查询方法都有对应的查询语句形式,如Select()suiying select

      4. 部分查询方法目前在C#中还没有对应的查询语句,如Count()和Max(),这时可以采用替代方案:

        1. 查询方法

        2. 查询语句+查询方法

                            一般情况下,建议使用可读性更好的查询语句

四、 LINQ查询子句

  1. LINQ查询字句的概述
    1. 查询表达式:是一种用查询语法表示的表达式,由一组用类似SQL的语法编写的句子组成,每个字句可以包含一个或多个C#表达式
      //LINQ查询表达式必须以from子句开头
      //并且必须以select或group子句结束,中间可以添加多个子句
      var lsit = from num in nums
              where num%2 != 0
              orderby num descending
              select num;

       

    2. LINQ查询表达式包含的子句

      from子句:指定查询操作的数据源和范围变量

      where子句:筛选元素的逻辑条件,返回值是一个bool类型

      select子句:指定查询结果的类型和表现形式

      orderby子句:对查询结果进行排序

      group子句:对查询结果进行分组

      into子句:提供一个临时标识符,该标识可以充当对join/group/select子句结果的引用

      join子句:连接多个查询操作的数据源

      let子句:引用用于存储查询表达式中的子表达式结果的范围变量

    3.  

      from子句

      1.LINQ查询表达式必须包含from子句,并且必须以from子句开头,from子句指定的数据源类型必须为IEnumerable、Ienumerable<T>或者两者的派生类型(如:数组、List<T>、ArrayList等)

      2.关于数据源,如果数据源是泛型类型,则编译器可以自动推算出范围变量的类型,如果数据源类型是非泛型类型,如ArrayList,则必须显示指定范围变量的数据类型

      static void Main(string[] args)
      {
          ArrayList values = new ArrayList();
          for(int i = 0;i < 10;i++){values.Add(i);}
          var list = from int item in values
                      where item%2 != 0
                      select item;
      }

      3.复合from子句查询:如果数据源(本身是一个序列)的元素还包含数据源(序列、列表等),如果要查询子数据源中的元素需要使用复合from子句

      static void Main(string[] args)
      {
          Student obj1 = new Student(){StuId = 1001,StiName = "学员1",ScoreList = new List<int>(){90,75,60}};
          Student obj2 = new Student(){StuId = 1002,StiName = "学员2",ScoreList = new List<int>(){97,83,70}};
          Student obj3 = new Student(){StuId = 1003,StiName = "学员3",ScoreList = new List<int>(){80,89,96}};
          List<Student> stuList = new List<Student>(){obj1,obj2,obj3};
          var result = from stu in stuList
                      from score in stu.ScoreList
                      where score >= 95
                      select stu;
          foreach(var item in result)
          {
              //输出分数包含95分以上的学生
          }
      }
      
      class Student
      {
          public int StuId{get;set;}
          public int Age{get;set;}
          public string StuName{get;set;}
          public List<int> ScoreList{get;set;}
      }

      4.多个from子句查询:若LINQ查询表达式包含两个或两个以上的独立数据源时,可以使用多个from子句查询所有数据源中的数据

      static void Main(string[] args)
      {
          Student obj1 = new Student(){StuId = 1001,StuName = "学员1"};
          Student obj2 = new Student(){StuId = 1009,StuName = "学员9"};
          Student obj3 = new Student(){StuId = 1012,StuName = "学员12"};
          Student obj4 = new Student(){StuId = 1003,StuName = "学员3"};
          Student obj5 = new Student(){StuId = 1019,StuName = "学员19"};
          Student obj6 = new Student(){StuId = 1006,StuName = "学员6"};
          
          List<Student> stuList1 = new List<Student>(){obj1,obj2,obj3};
          List<Student> stuList2 = new List<Student>(){obj4,obj5,obj6};
          
          //查询学号大于1010的学员
          var result = from stuL1 in stuList1 
                  where stu1.StuId > 1010
                  from stu2 in stuList2
                  where stu2.StuId> 1010
                  select new {stu1,stu2};
          //显示结果
          foreach(var item in result)
          {
              Console.WriteLine(item.stu1.StuName + " " +item.stu1.StuId);
              Console.WriteLine(item.stu2.StuName + " " +item.stu2.StuId);
          }
      }

       

五、LINQ高级查询

  1. 聚合类:Count,Max/Min,Average
    //Count返回集合项的数目
    static void Main(string[] args)
    {
        Student obj1 = new Student(){StuId = 1001,StuName = "学员1"};
        Student obj2 = new Student(){StuId = 1009,StuName = "学员9"};
        Student obj3 = new Student(){StuId = 1012,StuName = "学员12"};
        Student obj4 = new Student(){StuId = 1013,StuName = "学员13"};
        Student obj5 = new Student(){StuId = 1019,StuName = "学员19"};
        Student obj6 = new Student(){StuId = 1006,StuName = "学员6"};
        List<Student> stuList = new List<Student>(){obj1,obj2,obj3,obj4,obj5,obj6};
        
        var count1 = (from c in stuList 
                        where c.StuId > 1010
                        select c).Count();//混合模式
        var count2 = stuList
                        .Where(c => c.stuId > 1010)
                        .Count();//查询方法
    
        //输出结果
        Console.WriteLine("count1 = {0},count2 = {1}",count1,count2);
        Console.ReadLine();
    }
    
    //求最大,最小,平均值,总数的方法与上面一致

     

  2. 排序类:ThenBy
    //ThenBy复合排序
    static void Main(string[] args)
    {
        var stus1 = from s in stuList
                    orderby s.StuName,s.Age
                    select s;
        var stus2 = stuList
                    .OrderBy(s => s.StuName)
                    .ThenBy(s => s.Age)
                    .ThenBy(s => s.StuId)
                    .Select(p => p);
    }

     

  3. 分区类:Take(提取指定数量的项),TakeWhile(只要满足指定条件,就会返回序列的元素,然后跳过剩余元素),Skip(跳过指定数量的项并获取剩余的项),SkipWhile(只要满足指定条件,就会跳过序列的元素,然后跳过剩余元素)
    static void Main(string[] args)
    {
        int[] nums = {1,2,3,4,5,6,7,8,9};
        
        var list1 = nums.Skip(1).Take(3);//结果为2,3,4
        var list2 = nums.ShipWhile(i => i%3 != 0).TakeWhile(i => i%2 !=0);//结果为3
    }

     

  4. 集合类:Distinct(去重)
    static void Main(string[] args)
    {
        int[] nums = {1,2,6,5,6,2,7,8};
        
        var list = nums.Distinct();//结果为1,2,6,5,7,8
    }

     

  5. 生产类:Range(生成一个整数序列),Repeat(生成一个重复项的序列)
    static void Main(string[] args)
    {
        var nums1 = Enumerable.Range(1,10);//结果为1-10
        var nums2 = Enumerable.Repeat("LinQ best!",10);//结果为10个LinQ best!
    }

    注意:

  • Range/Repeat不是扩展方法,而是普通的静态方法

  • Range只能产生整数序列

  • Repeat可以产生泛型序列

  • 所有查询方法都放在System.Linq.Enumerable类中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值