21.3 基本子句

  既然LINQ查询语句同SQL查询语句一样,能够执行条件、排序等操作,这些操作就需要使用WHERE、ORDERBY等关键字,这些关键字在LINQ中是基本子句。同SQL查询语句中的WHERE、ORDER BY操作一样,都为元素进行整合和筛选。

21.3.1 from查询子句
  from子句是LINQ查询语句中最基本也是最关键的子句关键字,与SQL查询语句不同的是,from关键字必须在LINQ查询语句的开始。
1.from查询子句基础
后面跟随着项目名称和数据源,示例代码如下所示。

+展开
-C#
 var linqstr = from lq in str select lq;//form子句

  from语句指定项目名称和数据源,并且指定需要查询的内容,其中项目名称作为数据源的一部分而存在,用于表示和描述数据源中的每个元素,而数据源可以是数组、集合、数据库甚至是XML。值得一提的是,from子句的数据源的类型必须为IEnumerable、IEnumerable<T>类型或者是IEnumerable、IEnumerable<T>的派生类,否则from不能够支持LINQ查询语句。
  在.NET Framework中泛型编程中,List(可通过索引的强类型列表)也能够支持LINQ查询语句的from关键字,因为List实现了IEnumerable、IEnumerable<T>类型,在LINQ中可以对List类进行查询,示例代码如下所示。

+展开
-C#
        static void Main(string[] args)
        {
            List<string> MyList = new List<string>();//创建一个列表项
            MyList.Add("guojing");//添加一项
            MyList.Add("wujunmin");//添加一项
            MyList.Add("muqing"); //添加一项
            var linqstr = from l in MyList select l;//LINQ查询
            foreach (var element in linqstr)//遍历集合
            {
                Console.WriteLine(element.ToString());//输出对象
            }
            Console.ReadKey();
        }

  上述代码创建了一个列表项并向列表中添加若干项进行LINQ查询。由于List<T>实现了IEnumerable、IEnumerable<T>,所以List<T>列表项可以支持LINQ查询语句的from关键字,如图21-6所示。
from子句
图21-6 from子句
  顾名思义,from语句可以被理解为“来自”,而in可以被理解为“在哪个数据源中”,这样from语句就很好理解了,如from l in MyList select l语句可以翻译成“找到来自MyList数据源中的集合l”,这样就能够更加方便的理解from语句。
2.from查询子句嵌套查询
  在SQL语句中,为了实现某一功能,往往需要包含多个条件,以及包含多个SQL子句嵌套。在LINQ查询语句中,并没有and关键字为复合查询提供功能。如果需要进行复杂的复合查询,可以在from子句中嵌套另一个from子句即可,示例代码如下所示。

+展开
-C#
var linqstr = from lq in str from m in str2 select lq;//使用嵌套查询

  上述代码就使用了一个嵌套查询进行LINQ查询。在有多个数据源或者包括多个表的数据需要查询时,可以使用LINQfrom子句嵌套查询,数据源示例代码如下所示。

+展开
-C#
            List<string> MyList = new List<string>();//创建一个数据源
            MyList.Add("guojing");//添加一项
            MyList.Add("wujunmin");//添加一项
            MyList.Add("muqing"); //添加一项
            MyList.Add("yuwen");//添加一项
            List<string> MyList2 = new List<string>();//创建另一个数据源
            MyList2.Add("guojing's phone");//添加一项
            MyList2.Add("wujunmin's phone ");//添加一项
            MyList2.Add("muqing's phone ");//添加一项
            MyList2.Add("lupan's phone ");//添加一项

  上述代码创建了两个数据源,其中一个数据源存放了联系人的姓名的拼音名称,另一个则存放了联系人的电话信息。为了方便的查询在数据源中“联系人”和“联系人电话”都存在并且匹配的数据,就需要使用from子句嵌套查询,示例代码如下所示。

+展开
-C#
            var linqstr = from l in MyList from m in MyList2 where m.Contains(l) select l;//from子句嵌套查询
            foreach (var element in linqstr)//遍历集合元素
            {
                Console.WriteLine(element.ToString());//输出对象
            }
            Console.ReadKey();

  上述代码使用了LINQ语句进行嵌套查询,嵌套查询在LINQ中会被经常使用到,因为开发人员常常遇到需要面对多个表多个条件,以及不同数据源或数据源对象的情况,使用LINQ查询语句的嵌套查询可以方便的在不同的表和数据源对象之间建立关系。

21.3.2 where条件子句
  在SQL查询语句中可以使用where子句进行数据的筛选,在LINQ中同样包括where子句进行数据源中数据的筛选。where子句指定了筛选的条件,这也就是说在where子句中的代码段必须返回布尔值才能够进行数据源的筛选,示例代码如下所示。

+展开
-C#
var linqstr = from l in MyList where l.Length > 5 select l;//编写where子句

  LINQ查询语句可以包含一个或多个where子句,而where子句可以包含一个或多个布尔值变量,为了查询数据源中姓名的长度在6之上的姓名,可以使用where子句进行查询,示例代码如下所示。

+展开
-C#
        static void Main(string[] args)
        {
            List<string> MyList = new List<string>();//创建List对象
            MyList.Add("guojing");//添加一项
            MyList.Add("wujunmin");//添加一项
            MyList.Add("muqing"); //添加一项
            MyList.Add("yuwen"); //添加一项
            var linqstr = from l in MyList where l.Length > 6 select l;//执行where查询
            foreach (var element in linqstr)//遍历集合
            {
                Console.WriteLine(element.ToString());//输出对象
            }
            Console.ReadKey();
        }

  上述代码添加了数据源之后,通过where子句在数据源中进行条件查询,LINQ查询语句会遍历数据源中的数据并进行判断,如果返回值为true,则会在linqstr集合中添加该元素,运行后如图21-7所示。
where子句查询
图21-7 where子句查询
  当需要多个where子句进行复合条件查询时,可以使用“&&”进行where子句的整合,示例代码如下所示。

+展开
-C#
        static void Main(string[] args)
        {
            List<string> MyList = new List<string>();//创建List对象
            MyList.Add("guojing");//添加一项
            MyList.Add("wujunmin");//添加一项
            MyList.Add("muqing"); //添加一项
            MyList.Add("guomoruo");//添加一项
            MyList.Add("lupan");//添加一项
            MyList.Add("guof");//添加一项
            var linqstr = from l in MyList where (l.Length > 6 && l.Contains("guo"))||l=="lupan" select l;//复合查询
            foreach (var element in linqstr)//遍历集合
            {
                Console.WriteLine(element.ToString());//输出对象
            }
            Console.ReadKey();
        }

  上述代码进行了多条件的复合查询,查询姓名长度大于6并且姓名中包含guo的姓或者姓名是“lupan”的人,运行后如图21-8所示。
复合where子句查询
图21-8 复合where子句查询
  复合where子句查询通常用于同一个数据源中的数据查询,当需要在同一个数据源中进行筛选查询时,可以使用where子句进行单个或多个where子句条件查询,where子句能够对数据源中的数据进行筛选并将复合条件的元素返回到集合中。

21.3.3 select选择子句
  select子句同from子句一样,是LINQ查询语句中必不可少的关键字,select子句在LINQ查询语句中是必须的,示例代码如下所示。

+展开
-C#
var linqstr = from lq in str select lq; //编写选择子句

  上述代码中包括三个变量,这三个变量分别为linqstr、lq、str。其中str是数据源,linqstr是数据源中满足查询条件的集合,而lq也是一个集合,这个集合来自数据源。在LINQ查询语句中必须包含select子句,若不包含select子句则系统会抛出异常(除特殊情况外)。select语句指定了返回到集合变量中的元素是来自哪个数据源的,示例代码如下所示。

+展开
-C#
        static void Main(string[] args)
        {
            List<string> MyList = new List<string>();//创建List
            MyList.Add("guojing");//添加一项
            MyList.Add("wujunmin");//添加一项
            MyList.Add("guomoruo");//添加一项
            List<string> MyList2 = new List<string>();//创建List
            MyList2.Add("guojing's phone");//添加一项
            MyList2.Add("wujunmin's phone ");//添加一项
            MyList2.Add("lupan's phone ");//添加一项
            var linqstr = from l in MyList from m in MyList2 where m.Contains(l) select l;//select l变量
            foreach (var element in linqstr)//遍历集合
            {
                Console.WriteLine(element.ToString());//输出集合内容
            }
            Console.ReadKey();//等待用户按键
        }

  上述代码从两个数据源中筛选数据,并通过select返回集合元素,运行后如图21-9所示。
select子句
图21-9 select子句
  如果将select子句后面的项目名称更改,则结果可能不同,更改LINQ查询子句代码如下所示。

+展开
-C#
var linqstr = from l in MyList from m in MyList2 where m.Contains(l) select m;//使用select

  上述LINQ查询子句并没有select l变量中的集合元素,而是选择了m集合元素,则返回的应该是MyList2数据源中的集合元素,运行后如图21-10所示。
select子句
图21-10 select子句
  对于不同的select对象返回的结果也不尽相同,当开发人员需要进行复合查询时,可以通过select语句返回不同的复合查询对象,这在多数据源和多数据对象查询中是非常有帮助的。

21.3.4 group分组子句
  在LINQ查询语句中,group子句对from语句执行查询的结果进行分组,并返回元素类型为IGrouping<TKey,TElement>的对象序列。group子句支持将数据源中的数据进行分组。但进行分组前,数据源必须支持分组操作才可使用group语句进行分组处理,示例代码如下所示。

+展开
-C#
    public class Person
    {
        public int age; //分组条件
        public string name;//创建姓名字段
        public Person(int age,string name)//构造函数
        {
            this.age = age;//构造属性值age
            this.name = name;//构造属性值name
        }
    }

  上述代码设计了一个类用于描述联系人的姓名和年级,并且按照年级进行分组,这样数据源就能够支持分组操作。
注意:虽然数组也可以进行分组操作,因为其绝大部分数据源都能够支持分组操作,但是数组等数据源进行分组操作可能是没有意义的。
  这里同样可以通过List列表以支持LINQ查询,示例代码如下所示。

+展开
-C#
        static void Main(string[] args)
        {
            List<Person> PersonList = new List<Person>();
            PersonList.Add(new Person(21,"limusha"));//通过构造函数构造新对象
            PersonList.Add(new Person(21, "guojing"));//通过构造函数构造新对象
            PersonList.Add(new Person(22, "wujunmin"));//通过构造函数构造新对象
            PersonList.Add(new Person(22, "lupan"));//通过构造函数构造新对象
            PersonList.Add(new Person(23, "yuwen"));//通过构造函数构造新对象
            var gl = from p in PersonList group p by p.age;//使用group子句进行分组
            foreach (var element in gl)//遍历集合
            {
                foreach (Person p in element)//遍历集合
                {
                    Console.WriteLine(p.name.ToString());//输出对象
                }
            }
            Console.ReadKey();
        }

  上述代码使用了group子句进行数据分组,实现了分组的功能,运行后如图21-11所示。
group子句
图21-11 group子句
  正如图21-11所示,group子句将数据源中的数据进行分组,在遍历数据元素时,并不像前面的章节那样直接对元素进行遍历,因为group子句返回的是元素类型为IGrouping<TKey,TElement>的对象序列,必须在循环中嵌套一个对象的循环才能够查询相应的数据元素。
  在使用group子句时,LINQ查询子句的末尾并没有select子句,因为group子句会返回一个对象序列,通过循环遍历才能够在对象序列中寻找到相应的对象的元素,如果使用group子句进行分组操作,可以不使用select子句。

21.3.5 orderby排序子句
  在SQL查询语句中,常常需要对现有的数据元素进行排序,例如注册用户的时间,以及新闻列表的排序,这样能够方便用户在应用程序使用过程中快速获取需要的信息。在LINQ查询语句中同样支持排序操作以提取用户需要的信息。在LINQ语句中,orderby是一个词组而不是分开的,orderby能够支持对象的排序,例如按照用户的年龄进行排序时就可以使用orderby关键字,示例代码如下所示。

+展开
-C#
    public class Person //创建对象
    {
        public int age; //创建字段
        public string name;//创建字段
        public Person(int age,string name)//构造函数
        {
            this.age = age;//赋值字段
            this.name = name;
        }
    }

  上述代码同样设计了一个Person类,并通过age、name字段描述类对象。使用LINQ,同样要使用List类作为对象的容器并进行其中元素的查询,示例代码如下所示。

+展开
-C#
    class Program
    {
        static void Main(string[] args)
        {
            List<Person> PersonList = new List<Person>();//创建对象列表
            PersonList.Add(new Person(21,"limusha"));//年龄为21
            PersonList.Add(new Person(23, "guojing"));//年龄为23
            PersonList.Add(new Person(22, "wujunmin")); //年龄为22
            PersonList.Add(new Person(25, "lupan"));//年龄为25
            PersonList.Add(new Person(24, "yuwen"));//年龄为24
            var gl = from p in PersonList orderby p.age select p;//执行排序操作
            foreach (var element in gl)//遍历集合
            {
                Console.WriteLine(element.name.ToString());//输出对象
            }
            Console.ReadKey();
        }
    }

  上述代码并没有按照顺序对List容器添加对象,其中数据的显示并不是按照顺序来显示的。使用orderby关键字能够指定集合中的元素的排序规则,上述代码按照年龄的大小进行排序,运行后如图21-12所示。
orderby子句
图21-12 orderby子句
  orderby子句同样能够实现倒序排列,倒序排列在应用程序开发过程中应用的非常广泛,例如新闻等。用户关心的都是当天的新闻而不是很久以前发布的某个新闻,如果管理员发布了一个新的新闻,显示在最上方的应该是最新的新闻。在orderby子句中可以使用descending关键字进行倒序排列,示例代码如下所示。

+展开
-C#
var gl = from p in PersonList orderby p.age descending select p;//orderby语句

  上述代码将用户的信息按照其年龄的大小倒序排列,运行如图21-13所示。
orderby子句倒序
图21-13 orderby子句倒序
  orderby子句同样能够进行多个条件排序,如果需要使用orderby子句进行多个条件排序,只需要将这些条件用“,”号分割即可,示例代码如下所示。

+展开
-C#
var gl = from p in PersonList orderby p.age descending,p.name select p;//orderby语句


21.3.6 into连接子句
  into子句通常和group子句一起使用,通常情况下,LINQ查询语句中无需into子句,但是如果需要对分组中的元素进行操作,则需要使用into子句。into语句能够创建临时标识符用于保存查询的集合,示例代码如下所示。


+展开
-C#
        static void Main(string[] args)
        {
            List<Person> PersonList = new List<Person>();//创建对象列表
            PersonList.Add(new Person(21, "limusha"));//通过构造函数构造新对象
            PersonList.Add(new Person(21, "guojing"));//通过构造函数构造新对象
            PersonList.Add(new Person(22, "wujunmin"));//通过构造函数构造新对象
            PersonList.Add(new Person(22, "lupan"));//通过构造函数构造新对象
            PersonList.Add(new Person(23, "yuwen"));//通过构造函数构造新对象
            var gl = from p in PersonList group p by p.age into x select x;//使用into子句创建标识
            foreach (var element in gl)//遍历集合
            {
                foreach (Person p in element)//遍历集合
                {
                    Console.WriteLine(p.name.ToString());//输出对象
                }
            }
            Console.ReadKey();
        }

  上述代码通过使用into子句创建标识,从LINQ查询语句中可以看出,查询后返回的是一个集合变量x而不是p,但是编译能够通过并且能够执行查询,这说明LINQ查询语句将查询的结果填充到了临时标识符对象x中并返回查询集合给gl集合变量,运行结果如图21-14所示。
into子句
图21-14 into子句
  注意:into子句必须以select、group等子句作为结尾子句,否则会抛出异常。

21.3.7 join连接子句
  在数据库的结构中,通常表与表之间有着不同的联系,这些联系决定了表与表之间的依赖关系。在LINQ中同样也可以使用join子句对有关系的数据源或数据对象进行查询,但首先这两个数据源必须要有一定的联系,示例代码如下所示。

+展开
-C#
    public class Person//描述“人”对象
    {
        public int age; //描述“年龄”字段
        public string name;//描述“姓名”字段
        public string cid;//描述“车ID”字段
        public Person(int age,string name,int cid)//构造函数
        {
            this.age = age;//初始化
            this.name = name;//初始化
            this.cid = cid;
        }
    }
    public class CarInformaion//描述“车”对象
    {
        public int cid; //描述“车ID”字段
        public string type; //描述“车类型”字段
        public CarInformaion(int cid,string type)//初始化构造函数
        {
            this.cid = cid;初始化
            this.type = type; //初始化
        }
    }

  上述代码创建了两个类,这两个类分别用来描述“人”这个对象和“车”这个对象,CarInformation对象可以用来描述车的编号以及车的类型,而Person类可以用来描述人购买了哪个牌子的车,这就确定了这两个类之间的依赖关系。而在对象描述中,如果将CarInformation类的属性和字段放置到Person类的属性中,会导致类设计臃肿,同时也没有很好的描述该对象。对象创建完毕就可以使用List类创建对象,示例代码如下所示。

+展开
-C#
            List<Person> PersonList = new List<Person>(); //创建List类
            PersonList.Add(new Person(21, "limusha",1));//购买车ID为1的人
            PersonList.Add(new Person(21, "guojing",2)); //购买车ID为2的人
            PersonList.Add(new Person(22, "wujunmin",3)); //购买车ID为3的人
            List<CarInformaion> CarList = new List<CarInformaion>();
            CarList.Add(1, "宝马");//车ID为1的基本信息
            CarList.Add(2, "奇瑞");

  上述代码分别使用了List类进行对象的初始化,使用join子句就能够进行不同数据源中数据关联的操作和外连接,示例代码如下所示。

+展开
-C#
        static void Main(string[] args)
        {
            List<Person> PersonList = new List<Person>();//创建List类
            PersonList.Add(new Person(21, "limusha",1));//购买车ID为1的人
            PersonList.Add(new Person(21, "guojing",2)); //购买车ID为2的人
            PersonList.Add(new Person(22, "wujunmin",3));//购买车ID为3的人
            List<CarInformaion> CarList = new List<CarInformaion>();//创建List类
            CarList.Add(new CarInformaion(1,"宝马"));//车ID为1的车
            CarList.Add(new CarInformaion(2, "奇瑞"));//车ID为2的车
            var gl = from p in PersonList join car in CarList on p.cid equals car.cid select p;//使用join子句
            foreach (var element in gl)//遍历集合
            {
                Console.WriteLine(element.name.ToString());//输出对象
            }
            Console.ReadKey();
        }

  上述代码使用join子句进行不同数据源之间关系的创建,其用法同SQL查询语句中的INNER JOIN查询语句相似,运行后如图21-15所示。
join查询子句
图21-15 join查询子句

21.3.8 let临时表达式子句
  在LINQ查询语句中,let关键字可以看作是在表达式中创建了一个临时的变量用于保存表达式的结果,但是let子句指定的范围变量的值只能通过初始化操作进行赋值,一旦初始化之后就无法再次进行更改操作。示例代码如下所示。

+展开
-C#
        static void Main(string[] args)
        {
            List<Person> PersonList = new List<Person>();//创建List类
            PersonList.Add(new Person(21, "limusha",1)); //购买车ID为1的人
            PersonList.Add(new Person(21, "guojing",2)); //购买车ID为2的人
            PersonList.Add(new Person(22, "wujunmin",3));//购买车ID为3的人
            List<CarInformaion> CarList = new List<CarInformaion>();//创建List类
            CarList.Add(new CarInformaion(1,"宝马"));//车ID为1的车
            CarList.Add(new CarInformaion(2, "奇瑞"));//车ID为2的车
            var gl = from p in PersonList let car = from c in CarList select c.cid select p;//使用let 语句
            foreach (var element in gl)//遍历集合
            {
                Console.WriteLine(element.name.ToString());//输出对象
            }
            Console.ReadKey();
        }

  let就相当于是一个中转变量,用于临时存储表达式的值,在LINQ查询语句中,其中的某些过程的值可以通过let进行保存。而简单的说,let就是临时变量,如x=1+1、y=x+2这样,其中x就相当于是一个let变量,上述代码运行后如图21-16所示。
let子句
图21-16 let子句

评论(0)网络
阅读(41)喜欢(0)不喜欢(0)asp.net-linq