LINQ查询语句

在关系型数据库中,数据被组织放入规范化很好的表中,并通过简单而又强大的语言SQL来进行访问,SQL可以和数据库中任何数据配合使用,因为数据被放入表中,并遵从一些严格的规则。

然而在程序中却与数据库相反,保存在类对象或结构中的数据差异很大,因此,没有通用的查询语言来从数据结构中获取数据,从对象获取数据的方法一直都是作为程序的一部分而设计的,然而使用LINQ可以轻松查询对象集合。LINQ是.NET框架的扩展,它允许我们以使用SQL查询数据库的方式来查询数据集合。使用LINQ可以从数据库、程序对象的集合以及XML文档中查询数据。如下程序中语句中查询的定义就是from和select关键字,尽管查询在语句中定义,但直到最后的foreach语句请求其结果的时候才会执行。

   public class Program
    {
        static void Main(string[] args)
        {
            int[] numbers = { 2, 12, 5, 15 };

            IEnumerable<int> lowNums = from n in numbers where n < 10 select n;
            foreach (var x in lowNums)
                Console.WriteLine(x);
        }
    }

匿名类型

匿名类型也叫无名类类型,创建匿名类型的变量使用相同的形式,但是没有类名和构造函数,匿名类型经常用于LINQ查询的结果之中。

(1)匿名类型只能和局部变量配合使用,不能用于类成员
(2)由于匿名类型没有名字,我们必须使用var关键字作为变量类型
(3)不能设置匿名类型对象的属性,编译器为匿名类型创建的属性是只读的

当编译器遇到匿名类型的对象初始化语句时,它创建了一个有名字的新类类型,对于每一个成员初始化语句,它推断其类型并创建一个只读属性来访问它的值,属性和成员初始化语句具有相同的名字,匿名类型被构造后,编译器创建了这个类型的对象,如果编译器遇到了另一个具有相同的参数名、相同的推断类型和相同顺序的匿名类型,它会重用这个类型并直接创建新的实例,不会创建新的匿名类型。

LINQ查询时的俩种语法(方法语法、查询语法)

方法语法:使用标准的方法调用,这些方法是一组叫做标准查询运算符的方法,方法语法是命令式的,它指明了查询方法调用的顺序,编译器会将使用查询语法表示的查询,翻译为方法调用的形式,它和查询语法在运行时没有性能上的差异。

查询语法:看上去和SQL语句很相似,使用查询表达式形式书写,查询语法是声明式的,也就是说,查询描述的是你想返回的东西,但并没有指明如何执行这个查询。

    public class Program
    {
        static void Main(string[] args)
        {
            int[] numbers = { 2, 5, 28, 31, 17, 16, 42 };

            var numsQuery = from n in numbers where n < 20 select n;  //查询语法

            var numsMethod = numbers.Where(x => x < 20);  //方法语法

            int numsCount = (from n in numbers where n < 20 select n).Count();  //俩种方法的组合

            foreach (var x in numsQuery)
                Console.WriteLine(x);

            foreach(var x in numsMethod)
                Console.WriteLine(x);

            Console.WriteLine(numsCount);
        }
    }

查询表达式的结构

(1)子句必须按照一定的顺序出现
(2)from子句和select...group子句这俩部分是必需的
(3)在LINQ查询表达式中,select子句在表达式最后,这与SQL的SELECT语句在查询的开始处不一样,C#这么做的原因之一是让vs智能感应能在我们输入代码时给我们更多选项。

from子句

from子句指定了要作为数据源使用的数据集合,它还引入了迭代变量。

from子句与foreach语句的区别:
(1)foreach语句命令式地指定了要从第一个到最后一个按顺序地访问集合中的项,而from子句则声明式地规定集合中的每个项都要被访问,但没有假定以什么样的顺序
(2)foreach语句在遇到代码时就执行其主体,而from子句什么也不执行,它创建可以执行查询的后台代码对象,只有在程序的控制流遇到访问查询变量的语句时,才会执行查询

join子句

LINQ中的join子句和SQL中的JOIN子句很相似,联结操作接受俩个集合然后创建一个临时的对象集合,每一个对象包含原始集合对象中的所有字段。

join子句示例:

查询主体中的from...let...where

可选的from...let...where部分是查询主体的第一部分,可以由任意数量的3个子句来组合(from、let、where)

from:

查询表达式从from子句开始,后面跟查询主体,主体本身可以从任何数量的其他from子句开始,没个from子句都指定了一个额外的源数据集合并引入了要在之后运算的迭代变量。

let:

let子句接受一个表达式的运算符并且把它赋值给一个需要在其他运算中使用的标识符。

where:

where子句根据之后的运算来除去不符合指定条件的项。

orderby子句

orderby子句接受一个表达式并根据表达式按照顺序放回结果项,order子句的默认排序方式是升序,可以使用ascending()升序和descending(降序)关键字显示设置。

    public class Program
    {
        static void Main(string[] args)
        {
            int[] numbers = { 2, 5, 28, 31, 17, 16, 42 };

            var asc_qury = from n in numbers orderby n ascending select n;  //升序

            var desc_qury = from n in numbers orderby n descending select n;  //降序

            foreach (var v in asc_qury)
                Console.WriteLine(v);

            foreach (var v in desc_qury)
                Console.WriteLine(v);
        }
    }

group  by子句

group子句把select的对象根据一些标准进行分组,如果项包含在查询的结果中,它们就可以根据某个字段的值进行分组,作为分组的依据的属性叫做键(key),group子句返回的不是原始数据源中项的枚举,而是返回可以枚举已经形成的项的分组的可枚举类型,分组本身是可枚举类型,它们可以枚举实际的项。

        static void Main(string[] args)
        {
            var students = new[]
            {
                new {LName="Jones",FName="Mary",Age=19,Major="History" },
                new {LName="Smith",FName="Bob",Age=20,Major="CompSci" },
                new {LName="Fleming",FName="Carol",Age=21,Major="History" },
            };

            var query = from student in students group student by student.Major;

            foreach(var s in query)
            {
                Console.WriteLine("{0}", s.Key);  //分组键

                foreach (var t in s)
                    Console.WriteLine("  {0},{1}", t.LName, t.FName);
            }
        }

into子句

查询延续子句可以接受查询的一部分结果并赋予一个名字,从而可以在查询的另一部分中使用。

        static void Main(string[] args)
        {
            int[] _a = { 2, 3, 4, 5 };
            int[] _b = { 4, 5, 6 };

            var query = from a in _a
                        join b in _b on a equals b
                        into _c       //查询延续
                        from c in _c
                        select c;
            foreach (var v in query)
                Console.WriteLine(v);  //4,5
        }

标准查询运算符

(1)被查询的集合对象叫做序列,它必须实现IEnumerable<T>接口
(2)标准查询运算符使用方法语法
(3)一些运算符返回IEnumerable对象,而其他的一些运算符返回标量,返回标量的运算符立即执行,并返回一个值,而不是可枚举类型对象。

System.Linq.Enumerable类声明了标准查询运算符方法,然而这些方法不仅仅而是一些方法,它们是扩展了IEnumerable<T>泛型类的扩展方法,扩展方法如之前所介绍,扩展方法时公共的静态方法,尽管定义在一个类中,但目的是为另一个类(第一个形参)增加功能,该参数前必须有关键字this。

LINQ预定义的委托类型

很多标准运算符的参数中第一个参数是IEnumerable<T>对象的应用,之后的参数为泛型委托,泛型委托用于给运算符提供用户自定义的代码,LINQ定义了俩套泛型委托类型与标准查询运算符一起使用,即Func委托Action委托,我们用作实参的委托对象必须是这些类型或这些形式之一,并且总是在类型参数列表中的最后一个

使用:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章