LINQ查询基础

一、什么是LINQ

      LINQ是Language Integrate Query的缩写,意为语言集成查询,是微软在.Net Framework 4.5版中推出的主要特性之一。

      它为开发人员提供了统一的数据查询模式,并与.Net开发语言(如C#和VB.Net)集成,很大程度上简化了数据查询的编码和调试工作,提供了数据查询的性能。

      LINQ中查询表达式访问的是一个对象,而该对象可以表示为各种类型的数据源。比如SQL Server数据库,XML文档,ADO.NET数据集,以及内存中的数据集合等。

      在.NET类库中,LINQ相关类库都在System.Linq命名空间中,该命名空间提供支持使用LINQ进行查询的类和接口,其中主要是以下两个接口和两个类:

      IEnumerable<T>接口:它表示可以查询的数据集合,一个查询通常是逐个对集合对象中的元素进行筛选操作,返回一个新的IEnumerable<T>对象,用来保存查询结果。

      IQueryable<T>接口:它继承自IEnumerable<T>接口,表示一个可以查询的表达式目录树。

      Enumerable类:它通过对IEnumerable<T>提供扩展方法,实现LINQ标准查询运算。包括过滤、导航、排序、关联、求和、求最大值、求最小值等操作。

      Queryable类:它通过对IQueryable<T>提供扩展方法,实现LINQ标准查询运算。包括过滤、导航、排序、关联、求和、求最大值、求最小值等操作。

     根据数据源类型,可以将LINQ技术分为以下几个主要技术方向:

      1.LINQ to Object:数据源为实现了接口IEnumerable<T>和IQueryable<T>的内存数据集合,这也是LINQ的基础,本文将介绍着方面的内容。

      2.LINQ to ADO.NET:数据源为ADO.NET数据集,这里将数据库中的表结构映射到类结构,并通过ADO.NET从数据库中获取数据集到内存,通过LINQ进行数据查询。

      3.LINQ to XML:数据源为XML文档,这里通过XElement、XAttribute等类将XML文档数据加载到内存中,通过LINQ进行数据查询。

二、LINQ查询表达式

      在进行LINQ查询的编写之前,首先要了解查询表达式。查询表达式是LINQ查询的基础,也是最常用的编写LINQ查询的方法。查询表达式由查询关键字和对应的操作数组成。其中,查询关键字是常用的查询运算符。

      在C# 3.0中可以直接使用的查询关键字和功能如下表:

        

     

     1.用from子句指定数据源

        每个LINQ查询表达式都以from子句开始,from子句包括以下两个功能。

        (1)指定查询将采用的数据源

        (2)定义一个本地变量,表示数据源中单个数据

      单个from子句的编写格式为: from localVar in dataSource,其中,dataSource表示数据源,localVar表示单个元素。    

       示例代码如下:

            int[] array = { 1, 2, 4, 5, 7 };
            var query = from item in array 
select item; foreach (var item in query) { Console.WriteLine(item); }

      2.使用select子句指定目标数据源

         select子句指定在执行查询是产生的结果类型,其格式为:select element,其中elment参数指定查询结果中元素的类型及初始化方式。

         在进一步介绍select子句之前,先介绍一下本文示例中要用到的实体类:

public class LessonScore
    {
        /// <summary>
        /// 课程成绩
        /// </summary>
        public float Score { get; set; }
        /// <summary>
        /// 课程名称
        /// </summary>
        public string Lession { get; set; }

        public override string ToString()
        {
            return string.Format("{0}-----{1}分",Lession,Score);
        }
    }

public class Student
    {
        /// <summary>
        /// 学生名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 学生性别
        /// </summary>
        public string XingBie { get; set; }
        /// <summary>
        /// 学生年龄
        /// </summary>
        public int Age { get; set; }

        public List<LessonScore> Scores { get; set; }

        public override string ToString()
        {
             return string.Format("{0}---{1}---{2}",Name, XingBie,Age);
        }
    }

       select子句中要选择的目标类型不仅可以为数据源中的元素,还可以是该元素的不同操作结果,包括属性、方法和运算等。示例代码如下:

              Student[] students = {
                    new Student() {Name="乔峰",Age=20,XingBie="" },
                    new Student() {Name="欧阳修",Age=22,XingBie="" },
                    new Student() {Name="王五",Age=19,XingBie="" },
                    new Student() {Name="王丹",Age=20,XingBie="" },
                    new Student() {Name="倾国倾城",Age=18,XingBie="" }
                };
                var query1 = from student in students
                            select student;//整个元素作为查询结果
                foreach (var item in query1)
                {
                    Console.WriteLine(item);
                }

                var query2 = from student in students
                             select student.Name;//元素的属性作为查询结果
                foreach (var item in query2)
                {
                    Console.WriteLine(item);
                }

                var query3 = from student in students
                             select student.Name.Length;
                foreach (var item in query3)
                {
                    Console.WriteLine(item);
                }

       在某些特殊的场合下,往往查询结果只是临时使用一下,而查询结果的数据包括很多字段,并非一个简单的属性、方法返回值等。这时,可在select子句中使用匿名类型来解决这类问题。

       示例代码如下:

                //返回数据源中学生的姓名、年龄、姓名的长度
                //使用匿名类型方式返回
                var query4 = from student in students
                             select new {student.Name,student.Age,NameLen = student.Name.Length };
                foreach (var item in query4)
                {
                    Console.WriteLine(item);
                }

   3.使用where子句指定筛选条件

      通常一个LING查询不会如前面的示例代码那么简单,通常还需要对数据源中的元素进行过滤。只有符合条件的元素,才能参与查询结果的计算。

      LINQ中,where子句格式为:where expression,其中,expression是一个逻辑表达式,返回布尔值。

     where子句中的条件表达式,可以用&&和||指定多个条件的逻辑运算关系。其中,&&表示逻辑并,||表示逻辑或。

    示例代码:

                int[] array = { 1,3,9,5,16,20,54,60,18,37};
                var query1 = from item in array  //查询array中所以大于15的元素
                             where item > 15
                             select item;

                foreach (var item in query1)
                {
                    Console.Write("{0}, ",item);
                }
                Console.WriteLine();

                var query2 = from item in array  //查询array中所以大于10小于40的元素
                             where item > 10 && item < 40
                             select item;

                foreach (var item in query2)
                {
                    Console.Write("{0}, ", item);
                }
                Console.WriteLine();

                var query3 = from item in array  //查询array中小于10或者大于40的元素
                             where item < 10 || item > 40
                             select item;

                foreach (var item in query3)
                {
                    Console.Write("{0}, ", item);
                }

     4.使用orderby子句进行排序

       在一些场合,还需要对查询结果进行排序。在LINQ中,通过orderby子句对查询结果进行排序操作。

      orderby子句格式为:orderby element [ascending|descending],其中element是要进行排序的字段,可以是数据源中的数据,也可以是对元素操作的结果。

     [ascending|descending]是排序类型,ascending为升序,descending为降序,默认请客下为ascending。

     示例代码:

               int[] array = { 1, 3, 9, 5, 16, 20, 54, 60, 18, 37 };
                var query1 = from item in array //升序
                            orderby item
                            select item;
                foreach (var item in query1)
                {
                    Console.Write("{0}, ", item);
                }
                Console.WriteLine();

                var query2 = from item in array //降序
                             orderby item descending
                             select item;
                foreach (var item in query2)
                {
                    Console.Write("{0}, ", item);
                }
                Console.WriteLine();

      在LINQ中,orderby子句可以同时指定多规排序元素,还可以为每个元素指定独立的排序类型。orderby语句后的第一个排序元素为主要排序,第二个为次要排序,以此类推。

     示例代码如下:

               Student[] students = {
                    new Student() {Name="乔峰",Age=20,XingBie="" },
                    new Student() {Name="欧阳修",Age=22,XingBie="" },
                    new Student() {Name="王五",Age=19,XingBie="" },
                    new Student() {Name="王丹",Age=20,XingBie="" },
                    new Student() {Name="倾国倾城",Age=18,XingBie="" }
                };
                //主要按姓名长度从小到大,次要按年龄从大到小
                var query3 = from stu in students
                             orderby stu.Name.Length ascending, stu.Age descending
                             select stu;
                foreach (var item in query3)
                {
                    Console.WriteLine(item);
                }

     5.使用group子句进行分组

        在LINQ中,用group子句实现对查询结果的分组操作。group子句的常用格式为:group element by key。其中,element表示作为查询结果返回的元素,key表示分组条件。

       group子句返回类型为IGrouping<TKey,TElement>的查询结果。

       示例代码如下:

                Student[] students = {
                    new Student() {Name="乔峰",Age=22,XingBie="" },
                    new Student() {Name="欧阳修",Age=22,XingBie="" },
                    new Student() {Name="王五",Age=19,XingBie="" },
                    new Student() {Name="王丹",Age=19,XingBie="" },
                    new Student() {Name="倾国倾城",Age=19,XingBie="" }
                };
                //按学生性别分组
                var query1 = from stu in students
                             group stu by stu.XingBie;
                foreach (var grp in query1)
                {
                    Console.WriteLine(grp.Key);
                    foreach (var item in grp)
                    {
                        Console.WriteLine(item);
                    }
                }
                //按多条件分组,按性别和年龄分组
                var query2 = from stu in students
                             group stu by new { stu.XingBie, stu.Age };
                foreach (var grp in query2)
                {
                    Console.WriteLine("{0}---{1}",grp.Key.XingBie,grp.Key.Age);
                    foreach (var item in grp)
                    {
                        Console.WriteLine(item);
                    }
                }

         有时候需要对分组的结果进行排序、再次查询等操作。这就需要使用into关键字将group查询的结果保存到一个临时变量,并且必须使用select子句对其进行重新查询。

         into关键字语法为:group element by key into grp,其中,tmpGrp表示一个本地变量,用来临时保存group产生的结果,提供后面的LINQ子句使用。

   示例代码如下:

             Student[] students = {
                    new Student() {Name="乔峰",Age=22,XingBie="" },
                    new Student() {Name="欧阳修",Age=22,XingBie="" },
                    new Student() {Name="王五",Age=19,XingBie="" },
                    new Student() {Name="王丹",Age=19,XingBie="" },
                    new Student() {Name="倾国倾城",Age=19,XingBie="" }
                };

                var query3 = from stu in students
                             group stu by stu.Age into grp
                             orderby grp.Key descending
                             select grp;
                foreach (var grp in query3)
                {
                    Console.WriteLine("{0}岁的学生:", grp.Key);
                    foreach (var item in grp)
                    {
                        Console.WriteLine(item);
                    }
                }
原文地址:https://www.cnblogs.com/marshhu/p/6939763.html