Linq基本子句

由于个人在学校没有接触过Linq,而且在工作上运用Linq的时候也比较多,准备把LINQ的相关知识学习整理梳理一遍,希望能填补下这个知识点,也为未来减轻压力。

LINQ查询表达式使用C#常见的语言构造,从外观上看,和我们常用的SQL类似,并且查询表达式中的变量可以用匿名类型,所以在很多情况下,不需要指定变量类型就可以构建LINQ表达式。

LINQ的数据源可以是数据库对象或是XML流等,也可以使实现了IEnumerable或者泛型IEnumberable<T>接口的集合对象。

LINQ的基本语法包含如下的8个上下文关键字,如下:

关键字 说明
from 指定范围变量和数据源
where 根据bool表达式从数据源中筛选数据
select 指定查询结果中的元素所具有的类型或表现形式
group 对查询结果按照键值进行分组(IGrouping<TKey,TElement>)
into 提供一个标识符,它可以充当对join、group或select子句结果的引用
order 对查询出的元素进行排序(ascending/descending)
join 按照两个指定匹配条件来Equals连接两个数据源
let 产生一个用于存储查询表达式中的子表达式查询结果的范围变量

1、From子句:

如果要写一个LINQ表达式,就必须是以from子句开头。

            //单个form子句
            string[] values = { "学习使我快乐", "学习使我幸福", "爸爸叫我吃饭", "我充耳不闻" };
            var new_values = from value in values
                        where value.IndexOf("学习") > -1       //查询以"学习"开头的元素
                        select new { value, value.Length };
            foreach (var new_value in new_values)
            {
                Console.WriteLine("{0},{1}", new_value.value, new_value.Length);
            }
            Console.ReadKey();

            //使用LINQ查询List集合
            List<Person> personList = new List<Person>();
            personList.Add(new Person { Name = "张三", Age = 20, Gender = '' });
            personList.Add(new Person { Name = "李四", Age = 21, Gender = '' });
            personList.Add(new Person { Name = "王五", Age = 22, Gender = '' });

            var new_personList = from Person person in personList
                        where person.Age > 20       //查询年龄大于20的人
                        select person;
            foreach (Person new_person in new_personList)
            {
                Console.WriteLine("{0} 年龄:{1} 性别:{2}", new_person.Name, new_person.Age, new_person.Gender);
            }
            Console.ReadKey();
            //复合from子句
            List<Person> personList2 = new List<Person>()
            {
                new Person{ Name = "张三", Age = 20, Phone = new List<string>(){"666666","138******"}},
                new Person{ Name = "李四", Age = 21, Phone = new List<string>(){"777777","138******"}},
                new Person{ Name = "王五", Age = 22, Phone = new List<string>(){"888888","138******"}}
            };

            //person、phone都是查询变量,作用域为当前查询语句
            var new_personList2 = from person in personList2
                                  from phone in person.Phone
                                  where phone.IndexOf("6666") > -1       //查询个人电话集合以"6666"开头的人
                                  select person;
            foreach (var new_person in new_personList2)
            {
                Console.WriteLine("{0} 年龄{1}", new_person.Name, new_person.Age);
                foreach (var person_phone in new_person.Phone)
                {
                    Console.WriteLine("电话:{0}", person_phone);
                }
            }

            Console.ReadKey();

            //4多个from子句
            var personList3 = from Person person in personList
                         where person.Age > 21       //查询集合1年龄超过21的人
                         from Person person2 in personList2
                         where person2.Age == 21       //查询集合2年龄等于21的人
                         select new { person, person2 };//查询结果定制
            foreach (var new_person in personList3)
            {
                Console.WriteLine("{0}  {1}", new_person.person.Name, new_person.person2.Name);
            }

            Console.ReadKey();

运行结果如下:

2、Where子句:

where子句是LINQ表达式的元素筛选机制,除了开始和结束的位置,它几乎可以出现在LINQ表达式的任意位置上。在一个LINQ表达式中,可以有where子句,也可以没有;可以有一个,也可以有多个;多个where子句之间的逻辑关系相当于逻辑“与”,每个where子句可以包含1个或多个bool逻辑表达式,这些条件成为谓词,谓词逻辑之间用的是“&&”或“||”等而不是SQL中的and 、or。

            //常见的where语句
            List<Person> personList = new List<Person>()
            {
                new Person(){ Name = "张三三", Age = 20, Phone = "555555"},
                new Person(){ Name = "李四", Age = 21, Phone = "666666"},
                new Person(){ Name = "王五", Age = 22, Phone = "777777"}
            };

            var new_personList = from person in personList
                                 where (person.Name.Length == 3 || person.Name.Substring(0, 1) == "") && person.Age > 20       //查询姓名长度为3或姓名以"李"开头且年龄大于20的人
                                 select new { person.Name, person.Age };
            foreach (var new_person in new_personList)
            {
                Console.WriteLine("{0},{1}", new_person.Name, new_person.Age);
            }

            Console.ReadKey();

            //在where子句中使用自定义函数
            var new_personList2 = from Person person in personList
                         where person.Name.Length == 2
                         && Check(person.Name)       //查询姓名长度为2且符合自定义函数限定后的人
                         select person;
            foreach (var new_person in new_personList2)
            {
                Console.WriteLine("{0},{1},{2}", new_person.Name, new_person.Age, new_person.Phone);
            }
            Console.ReadKey();

            //动态谓词的筛选
            //定义动态谓词数组,在实际开发中可以动态获得
            string[] names = { "李四", "XXX", "***", "@@@", "一些敏感词" };

            var new_personList3 = from Person person in personList
                         where !names.Contains(person.Name)       //查询姓名不包含集合元素的人
                         select person;

            foreach (var new_person in new_personList3)
            {
                Console.WriteLine("{0} 年龄:{1},电话:{2}", new_person.Name, new_person.Age, new_person.Phone);
            }
            Console.ReadKey();
        //自定义函数
        static bool Check(string name)
        {
            if (name.Substring(0, 1) == "")
                return false;
            return true;
        }

运行结果如下:

 3、Select子句:

在select子句上可以非常灵活的处理查询到的元素,然后再把结果返回。

            List<Person> personList = new List<Person>()
            {
                new Person(){ Name = "张三", Age = 20, Phone = "555555"},
                new Person(){ Name = "李四", Age = 21, Phone = "666666"},
                new Person(){ Name = "王五", Age = 22, Phone = "777777"}
            };

            //常见的select语句
            var new_personList = from person in personList
                                 where person.Age >= 22 && person.Age <= 30       //查询年龄大于等于22小于等于30的人
                                 select new { person.Name, person.Age };       //处理查询结果,返回查到的人的姓名和年龄

            foreach (var new_person in new_personList)
            {
                Console.WriteLine(new_person.Name + “ 年龄:” + new_person.Age);
            }
            Console.ReadKey();

            //对查询到的结果集进行替换
            var new_personList2 = from person in personList
                                  where person.Age >= 21 && person.Age <= 30       //查询年龄大于等于22小于等于30的人
                                  select person.Name.Replace("", "");       //处理查询结果,返回查到的人的姓名替换后的结果

            foreach (var new_person in new_personList2)
            {
                Console.WriteLine(new_person);
            }
            Console.ReadKey();

            //在select子句中使用自定义函数
            var new_personList3 = from person in personList
                                  where person.Age >= 20 && person.Age <= 21       //查询年龄大于等于20小于等于21的人
                                  select MyDesc(person.Name);       //处理查询结果,返回自定义函数处理后的人的姓名

            foreach (var new_person in new_personList3)
            {
                Console.WriteLine(new_person);
            }
            Console.ReadKey();

            //对查询结果进行投影
            var new_personList4 = from person in personList
                                  where person.Age >= 21 && person.Age <= 22       //查询年龄大于等于21小于等于22的人
                                  select new NewPerson { Name = "我的名字叫:" + person.Name, Age = person.Age + 1 };       //处理查询结果,返回投影结果

            foreach (var new_person in new_personList4)
            {
                Console.WriteLine(new_person.Name + new_person.Age);
            }
            Console.ReadKey();
        static string MyDesc(string s)
        {
            return s + "好帅";
        }
    public class NewPerson
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

运行结果如下:

 4、Group子句:

LINQ表达式必须以from子句开头,以select或group子句结束,所以除了使用select来返回结果外,也可以使用group子句来返回元素分组后的结果。group子句返回的是一个基于IGrouping<TKey,TElement>泛型接口的对象序列。

注意:语法和SQL的group有点区别。

            List<Person> personList = new List<Person>()
            {
                new Person(){ Name = "张一", Age = 20, Phone = "333333"},
                new Person(){ Name = "张二", Age = 21, Phone = "444444"},
                new Person(){ Name = "张三", Age = 22, Phone = "555555"},
                new Person(){ Name = "李四", Age = 23, Phone = "666666"},
                new Person(){ Name = "李五", Age = 24, Phone = "777777"},
                new Person(){ Name = "赵六", Age = 25, Phone = "888888"},
                new Person(){ Name = "田七", Age = 26, Phone = "999999"},
            };

            var new_personList = from person in personList
                                 group person by person.Name.Substring(0, 1);       //按姓氏进行分组

            //遍历键值和键值所属元素
            foreach (IGrouping<string, Person> new_person in new_personList)
            {
                Console.WriteLine();
                Console.WriteLine("姓:{0} ", new_person.Key);
                foreach (var p in new_person)
                {
                    Console.WriteLine("{0} 年龄:{1}  电话:{2}", p.Name, p.Age, p.Phone);
                }
            }
            Console.ReadKey();

            Console.WriteLine();
            Console.WriteLine("-----------------------------------");

            var new_personList2 = from person in personList
                                  group person by person.Age > 23;       //按年龄是否大于23进行分组

            foreach (IGrouping<bool, Person> new_person in new_personList2)
            {
                Console.WriteLine();
                Console.WriteLine("年龄 {0} 23 ", new_person.Key ? "大于" : "小于");
                foreach (var p in new_person)
                {
                    Console.WriteLine("{0} 年龄:{1}  电话:{2}", p.Name, p.Age, p.Phone);
                }
            }
            Console.ReadKey();

运行结果如下:

 5、Into子句:

into子句作为一个临时标识符,用于group、select、join子句中充当其结果的引用。

            List<Person> personList = new List<Person>()
            {
                new Person(){ Name = "张一", Age = 20, Phone = "333333"},
                new Person(){ Name = "张二", Age = 21, Phone = "444444"},
                new Person(){ Name = "张三", Age = 12, Phone = "555555"},
                new Person(){ Name = "李四", Age = 23, Phone = "666666"},
                new Person(){ Name = "李五", Age = 14, Phone = "777777"},
                new Person(){ Name = "赵六", Age = 25, Phone = "888888"},
                new Person(){ Name = "田七", Age = 16, Phone = "999999"},
            };

            //into用于group子句
            var new_personList = from person in personList
                                 group person by person.Name.Substring(0, 1) into person_group       //相当于分组后的组名
                                 select person_group;

            foreach (var persontGroup in new_personList)
            {
                Console.WriteLine("姓:{0} ", persontGroup.Key);
                foreach (var p in persontGroup)
                {
                    Console.WriteLine("{0} 电话:{1}", p.Name, p.Phone);
                }
            }
            Console.ReadKey();
            Console.WriteLine();

            //select子句中的into子句
            var new_personList2 = from person in personList
                                  select new { NewName = person.Name, NewAge = person.Age } into newperson       //相当于创建一个新的对象
                                  orderby newperson.NewAge
                                  select newperson;
            
            foreach (var persontGroup in new_personList2)
            {
                Console.WriteLine("{0} 年龄:{1}", persontGroup.NewName, persontGroup.NewAge);
            }

            Console.ReadKey();

运行结果如下:

6、OrderBy子句:

按照元素的一个或多个属性对元素进行排序。

            List<Person> personList = new List<Person>()
            {
                new Person(){ Name = "张一", Age = 20, Phone = "333333"},
                new Person(){ Name = "张二二", Age = 20, Phone = "444444"},
                new Person(){ Name = "张三", Age = 12, Phone = "555555"},
                new Person(){ Name = "李四", Age = 23, Phone = "666666"},
                new Person(){ Name = "李五", Age = 14, Phone = "777777"},
                new Person(){ Name = "赵六", Age = 25, Phone = "888888"},
                new Person(){ Name = "田七", Age = 16, Phone = "999999"},
            };

            //按照年龄排序
            var new_personList = from person in personList
                                 orderby person.Age       //默认升序ascending,如果要降序要加上descending
                                 select person;

            foreach (var new_person in new_personList)
            {
                Console.WriteLine("{0} 年龄:{1} 电话:{2}", new_person.Name, new_person.Age, new_person.Phone);
            }
            Console.ReadKey();
            Console.WriteLine();

            //按照年龄进行降序排序,按照名字字数进行次要排序
            var new_personList2 = from person in personList
                                  orderby person.Age descending, person.Name.Length descending
                                  select person;

            foreach (var new_person in new_personList2)
            {
                Console.WriteLine("{0} 年龄:{1} 电话:{2}", new_person.Name, new_person.Age, new_person.Phone);
            }
            Console.ReadKey();

运行结果如下:

 7、Let子句:

let子句用于在LINQ表达式中存储子表达式的计算结果。

            List<Person> personList = new List<Person>()
            {
                new Person(){ Name = "张一", Age = 20, Phone = "333333"},
                new Person(){ Name = "张二二", Age = 20, Phone = "444444"},
                new Person(){ Name = "张三", Age = 12, Phone = "555555"},
                new Person(){ Name = "李四", Age = 23, Phone = "666666"},
                new Person(){ Name = "李五", Age = 14, Phone = "777777"},
                new Person(){ Name = "赵六", Age = 25, Phone = "888888"},
                new Person(){ Name = "田七", Age = 16, Phone = "999999"},
            };

            //使用let子句创建范围变量g,并通过g构建查询表达式
            var new_personList = from person in personList
                                 let g = person.Name.Substring(0, 1)
                                 where g == "" || g == ""
                                 select person;

            foreach (var new_person in new_personList)
            {
                Console.WriteLine("{0} 年龄:{1} 电话:{2}", new_person.Name, new_person.Age, new_person.Phone);
            }
            Console.ReadKey();
            Console.WriteLine();

            //也可以不使用let,上面的语句等效于下
            var new_personList2 = from person in personList
                                  where person.Name.Substring(0, 1) == "" || person.Name.Substring(0, 1) == ""
                                  select person;

            foreach (var new_person in new_personList2)
            {
                Console.WriteLine("{0} 年龄:{1} 电话:{2}", new_person.Name, new_person.Age, new_person.Phone);
            }
            Console.ReadKey();

运行结果如下:

8、Join子句:

join子句能将两个数据源中元素可以进行相等比较的两个属性进行关联。使用equals关键字进行相等比较,而不是常用的双等号。

            //定义两个数据源
            List<Person> personList = new List<Person>()
            {
                new Person(){ Name = "张三", Age = 12, Phone = "555555"},
                new Person(){ Name = "李四", Age = 23, Phone = "666666"},
                new Person(){ Name = "王五", Age = 14, Phone = "777777"},
                new Person(){ Name = "赵六", Age = 25, Phone = "888888"},
                new Person(){ Name = "田七", Age = 16, Phone = "999999"},
            };

            List<PersonFile> personFileList = new List<PersonFile>()
            {
                new PersonFile(){ Name = "张三", File = "三好学生"},
                new PersonFile(){ Name = "李四", File = "班长"},
                new PersonFile(){ Name = "王五", File = "学习委员"},
                new PersonFile(){ Name = "赵六", File = "差生"}
            };

            //根据姓名进行内连接
            var new_personList = from person in personList
                                 join file in personFileList on person.Name equals file.Name
                                 select new { Name = person.Name, file = file.File, Age = person.Age };

            foreach (var new_person in new_personList)
            {
                Console.WriteLine("{0} {1} 年龄:{2}", new_person.Name, new_person.file, new_person.Age);
            }
            Console.ReadKey();
            Console.WriteLine();

            //等效于前面的多个from的效果
            var new_personList2 = from person in personList
                                  from file in personFileList
                                  where person.Name == file.Name
                                  select new { Name = person.Name, File = file.File, Age = person.Age };

            foreach (var new_person in new_personList2)
            {
                Console.WriteLine("{0} {1} 年龄:{2}", new_person.Name, new_person.File, new_person.Age);
            }
            Console.ReadKey();
            Console.WriteLine();

            //根据姓名进行分组连接
            var new_personList3 = from person in personList
                                  join file in personFileList on person.Name equals file.Name into person_group
                                  select new { Name = person.Name, Files = person_group };

            foreach (var new_person in new_personList3)
            {
                Console.WriteLine(new_person.Name);
                foreach (var p in new_person.Files)
                {
                    Console.WriteLine(p.File);
                }
            }
            Console.ReadKey();
            Console.WriteLine();

            //根据姓名进行左外连接
            var new_personList4 = from person in personList
                                  join file in personFileList on person.Name equals file.Name into person_group
                                  from position in person_group.DefaultIfEmpty()
                                  select new { Name = person.Name, File = position == null ? "" : position.File };
            foreach (var new_person in new_personList4)
            {
                Console.WriteLine("{0}  {1}  ", new_person.Name, new_person.File);
            }
            Console.ReadKey();

运行结果如下:

 

 对Linq的基本子句用法学习和总结完毕,还有待继续练习达到灵活运行!

原文地址:https://www.cnblogs.com/jiechou/p/9175794.html