C#进阶之LINQ(2)Linq查询语句与查询方法

(一)Linq基础

1)Linq解决的问题

  • 面向对象编程语言与数据访问方法长期分离,以嵌入式的方式开发,例如:在这里插入图片描述
  • 编程语言中的数据类型与数据库中的数据类型形成两套体系,如:C#中的字符串string 在SQL中使用NVarchar/ Varchar/ Char来表示;
  • SQL和XML都有各自的查询语言,而对象没有自己的查询语言,如要从List<>集合或者数组中找到符合要求的元素,非常困难;

2)什么是Linq

  • Linq(Language Integrated Query, 语言集成查询)

    • 是微软公司提供的一项新技术,能够将查询功能直接引入到C#、VB.NET等编程语言中;
    • 查询操作可以通过编程语言自身来表示,而不是嵌入字符串SQL语句;
  • Linq 主要包含以下三个部分:

    • Linq to Objects 主要负责对象的查询;
    • Linq to XML 主要负责XML的查询;
    • Linq to ADO.NET主要负责数据库的查询:
      • (1) Linq to SQL (目前已经没人使用)
      • (2) Linq to DataSet
      • (3) Linq to Entities(重点学
  • Linq所在命名空间:

    • System.Linq; 该命名空间已经由系统自动引入;
    • 因此微软默认建议多使用Linq技术查询;
Linq的组成架构:

在这里插入图片描述

3)采用Linq技术与不采用Linq技术的对比

<1> 不使用Linq技术
using System;
using System.Collections.Generic;

namespace LinqDemo
{
    class Program
    {
        //找出所有的奇数
        static void Main(string[] args)
        {
            int[] nums = { 1, 7, 2, 6, 5, 4, 9, 13, 20 };
            List<int> list = new List<int>();
            foreach (var item in nums)
            {
                if (item % 2 == 1)
                    list.Add(item);
            }
            list.Sort();
            list.Reverse();
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
        }
    }
    
}

<2> 使用Linq技术

查询的时候,可以采用优化的算法,提高查询的效率;

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums = { 1, 7, 2, 6, 5, 4, 9, 13, 20 };
            var list = from num in nums
                       where num % 2 == 1
                       orderby num ascending
                       select num;
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
        }
    }
}

(二)Linq查询方法详解

1) 获取数据:扩展方法Select()

Select()是一个泛型扩展方法;
Select()方法使用的时候,要求传递一个委托实例(委托实例就是一个方法)

应用:

在这里插入图片描述

注意:数组、泛型集合都可以使用扩展方法Select();
using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums = { 1, 9, 78, 55, 45, 23, 56, 89, 12, 32, 33 };
            var list = nums.Select(item => item * item);
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
        }
    }
    
}

2)筛选数据:where() 方法

  • where()方法是一个扩展泛型方法;
  • where()方法使用的时候要求传递一个委托实例,但是该实例是一个判断条件,因此返回的类型必须是bool类型;
应用:

在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums = { 1, 9, 78, 55, 45, 23, 56, 89, 12, 32, 33 };
            var list = nums.Where(item => item % 2 == 1).Select(i => i * i);
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
        }
    }
    
}

3)排序数据:OrderBy()

  • OrderBy()是一个扩展方法;
  • OrderBy()里面的参数要求传递一个排序的字段,默认按照升序排序;
    如果想降序排序,可以使用OrderByDescending方法;
应用:

在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums = { 1, 9, 78, 55, 45, 23, 56, 89, 12, 32, 33 };
            var list = nums.Where(item => item % 2 == 0).Select(item => item * 2).OrderBy(item => item);
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] names = { "张三", "李四", "郭保彦", "刘宁", "上海", "北京" };
            var list = names.Where(item => item.Length == 2).Select(item => item)
                .OrderBy(item => item.Substring(0, 1));
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
        }
    }
}

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

  • OrderBy()是一个扩展方法;
  • OrderBy()里面的参数要求传递一个分组的字段
应用:

在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] names = { "张三", "李四", "网三三", "李思思", "上海", "北京" };
            var list = names.Select(item => item)
                .OrderBy(item => item.Substring(0, 1)).GroupBy(item=>item.Length);
            //遍历的时候需要注意,需要两层循环
            foreach (var item in list)
            {
                Console.WriteLine("分组字段:{0}", item.Key);
                foreach (var i in item)
                {
                    Console.WriteLine(i);
                }
            }
        }
    }
}

(三)Linq查询时机与查询形式

1)查询步骤:

步骤:获取数据源、定义查询、执行查询;
在这里插入图片描述

结论:
  • 定义查询以后,查询并没有立即执行,而是直到需要枚举结果(遍历)时,才真正执行;
  • 这种方式称之为“延迟执行”

2) 使用“聚合扩展方法”返回单一结果,强制查询立即执行

在这里插入图片描述

3)Linq查询的两种形式

<1> Method Syntax,查询方法方式
  • 主要利用System.Linq.Enumerable类中定义的扩展方法和Lambda表达式方式进行查询;
  • 在此之前所用的查询都是这种方法;
<2> Query Syntax,查询语句方式
  • 一种更接近于SQL语法的查询方式,可读性更好;
  • 查询语句最后还是要被翻译为查询方法;

在这里插入图片描述

注意:

在这里插入图片描述

(四)Linq查询子句

1)Linq查询子句概述

<1> 查询表达式
  • 是一种用查询语法表示的表达式,有一组用于类似于SQL的语法编写的句子组成;
  • 每个句子可以包含一个或者多个C#表达式;

在这里插入图片描述

<2> Linq查询表达式包含的子句:
  1. from子句:指定查询操作的数据源和范围变量;
  2. where子句:筛选元素的逻辑条件,返回值是一个bool类型;
  3. select子句:指定查询结果的类型和表现形式;
  4. orderby子句:对查询结果进行排序;
  5. group子句:对查询结果进行分组;
  6. into子句:提供一个临时标识符,该表示可充当对 join/ group/ select 子句结果的引用;
  7. join子句:连接多个查询操作的数据源;
  8. let子句:引入用于存储查询表达式中的子表达式结果的范围变量;

2)from子句

<1> 概述:
  • Linq查询表达式必须包含from子句,并且作为开头;
  • from子句指定的数据源必须为IEnumerable、Ienumerable<>或者两者的派生类型(例如:数组、集合List<>、ArrayList等)
    在这里插入图片描述
<2> 数据源
  • 如果数据源是泛型类型,则编译器可以自动推断出范围变量的类型,比如上面的num类型为int;
  • 如果数据源为非泛型类型,如ArrayList,则必须显式地指定范围变量的数据类型;
    在这里插入图片描述
<3> 复合from子句查询

如果数据源(本身是一个序列)的元素还包含子数据源(如序列、列表等,如果要查询子数据源的元素),则需要使用复合from子句;
在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Student obj1 = new Student()
            {
                StudentId = 101,
                StudentName = "zhansan",
                ScoreList = new List<int>() { 78, 89, 99}
            };

            Student obj2 = new Student()
            {
                StudentId = 102,
                StudentName = "LiuNing",
                ScoreList = new List<int>() { 88, 66, 78 }
            };

            Student obj3 = new Student()
            {
                StudentId = 103,
                StudentName = "guo",
                ScoreList = new List<int>() { 100, 89, 78 }
            };

            //将学员封装到集合中
            List<Student> stuList = new List<Student>() { obj1, obj2, obj3 };
            //查询95分以上的学员
            var result = from stu in stuList
                         from score in stu.ScoreList
                         where score >= 95
                         select stu;
            
            //显示查询结果
            foreach (var item in result)
            {
                Console.WriteLine(item.StudentName);
            }
        }
    }
}

<4> 多个from子句查询

若Linq查询表达式包含两个或两个以上的独立数据源时,可以使用多个from子句查询所有数据源中的数据;
在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Student obj1 = new Student()
            {
                StudentId = 117,
                StudentName = "zhansan",
               
            };

            Student obj2 = new Student()
            {
                StudentId = 102,
                StudentName = "LiuNing",
               
            };

            Student obj3 = new Student()
            {
                StudentId = 103,
                StudentName = "guo",
                
            };

            Student obj4 = new Student()
            {
                StudentId = 104,
                StudentName = "liu",

            };

            Student obj5 = new Student()
            {
                StudentId = 105,
                StudentName = "yi",

            };

            Student obj6 = new Student()
            {
                StudentId = 115,
                StudentName = "tian",

            };

            //将学员封装到集合中
            List<Student> stuList1 = new List<Student>() { obj1, obj2, obj3 };
            List<Student> stuList2 = new List<Student>() { obj4, obj5, obj6 };
            //查询95分以上的学员
            var result = from stu1 in stuList1
                         where stu1.StudentId > 110
                         from stu2 in stuList2
                         where stu2.StudentId > 110
                         select new { stu1, stu2 };
            //显示查询结果
            foreach (var item in result)
            {
                Console.WriteLine(item.stu1.StudentName);
                Console.WriteLine(item.stu2.StudentName);
            }
        }
    }
}

3)其他子句

在这里插入图片描述

(五)Linq高级查询

在这里插入图片描述

1)Count返回集合项的数目

在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Student obj1 = new Student()
            {
                StudentId = 117,
                StudentName = "zhansan",
               
            };

            Student obj2 = new Student()
            {
                StudentId = 102,
                StudentName = "LiuNing",
               
            };

            Student obj3 = new Student()
            {
                StudentId = 103,
                StudentName = "guo",
                
            };

            Student obj4 = new Student()
            {
                StudentId = 104,
                StudentName = "liu",

            };

            Student obj5 = new Student()
            {
                StudentId = 105,
                StudentName = "yi",

            };

            Student obj6 = new Student()
            {
                StudentId = 115,
                StudentName = "tian",

            };

            //将学员封装到集合中
            List<Student> stuList1 = new List<Student>() { obj1, obj2, obj3, obj4, obj5, obj6 };
            //查询
            var result = (from stu1 in stuList1
                          where stu1.StudentId > 102
                          select stu1).Count();
            var result1 = stuList1.Where(item => item.StudentId > 102).Count();

            //显示查询结果
            Console.WriteLine(result);
            Console.WriteLine(result1);
        }
    }
}

2)Max/Min/Average/Sum【数学上】

在这里插入图片描述

3)排序类

ThenBy提供复合排序条件;
在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Student obj1 = new Student()
            {
                StudentId = 117,
                StudentName = "zhansan",
                Age = 16
            };

            Student obj2 = new Student()
            {
                StudentId = 102,
                StudentName = "LiuNing",
                Age = 18
            };

            Student obj3 = new Student()
            {
                StudentId = 103,
                StudentName = "guo",
                Age = 21
            };

            Student obj4 = new Student()
            {
                StudentId = 104,
                StudentName = "liu",
                Age = 89
            };

            Student obj5 = new Student()
            {
                StudentId = 105,
                StudentName = "yi",
                Age = 78
            };

            Student obj6 = new Student()
            {
                StudentId = 115,
                StudentName = "tian",
                Age = 56
            };

            //将学员封装到集合中
            List<Student> stuList1 = new List<Student>() { obj1, obj2, obj3, obj4, obj5, obj6 };
            //查询
            var result = from s in stuList1
                         orderby s.Age, s.StudentName
                         select s;
            var result1 = stuList1.OrderBy(item => item.Age).ThenBy(item => item.StudentName).Select(item => item);
            //显示查询结果
            foreach (var item in result)
            {
                Console.WriteLine(item.StudentName);
            }
            Console.WriteLine("------------------");
            foreach (var item in result1)
            {
                Console.WriteLine(item.StudentName);
            }
        }
    }
}

4)分区类查询

  • Take 提取支墩数量的项;
  • Skip 跳过指定数量的项并获取剩余的项;
  • TakeWhile 只要满足指定条件,就会返回序列的元素,然后跳过剩余的元素;
  • SkipWhile 只要满足指定的条件,就跳过序列中的元素,然后返回剩余元素;
    在这里插入图片描述
using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            var list = nums.SkipWhile(i => i % 3 != 0).TakeWhile(i => i % 2 != 0).Select(item => item);
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
        }
    }
}

5)集合类查询Distinct

Distinct 去掉集合中的重复项;
在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9 };
            var list = nums.Distinct();
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
        }
    }
}

6) 生成类查询

  • Range生成一个整数序列;
    Repeat生成一个重复项的序列;
    在这里插入图片描述
注意问题:
  • Range/Repeat不是扩展方法,而是普通的静态方法;
  • Range 只能产生整数序列;
  • Repeat可以产生泛型序列;
  • 所有的查询方法都存放在System.Linq.Enumerable静态类中;
发布了66 篇原创文章 · 获赞 2 · 访问量 6670

猜你喜欢

转载自blog.csdn.net/forever_008/article/details/104146036