LinQ基础
什么是LINQ
引出
LINQ能够解决什么问题
NET平台开发中一直存在如下情况
- 面向对象编程语言与数据访问方法长期分离,以嵌入式的方式开发。例如:
- 编程语言中的数据类型与数据库中的数据类型形成两套体系。
- 例如:C#中字符串string在SQL中用NVarchar/Varchar/Char来表示。
- SQL和XML都有各自的查询语言,而对象没有自己的查询语言。
- 比如要从List<T>集合或数组中找到符合要求的元素,非常困难。
LINQ将重点解决以上问题
定义
LINQ(Language Integrated Query,语言集成查询)
- 是微软公司提供的一项新技术,能够将查询功能直接引入到C#、VB.NET等变成语言中。
- 查询操作可以通过编程语言自身来表示,而不是嵌入字符串SQL语句。
LINQ主要包含以下三个部分
- LINQ to Objects主要负责对象的查询
- LINQ to XML主要负责XML的查询
- LINQto ADO.NET主要负责数据库的查询
- (1)LINQ to SQL(目前已经没有人在使用)
- (2)LINQ to DataSet
- (3)LINQ to Entities(重点学习)
LINQ所在命名空间
- System.Linq;该命名空间已经由系统自动引入
- 因此微软默认建议你多使用Linq技术查询
LINQ的组成架构
对比:
不采用LINQ技术的查询方法 | 使用LINQ查询方法PK刚才的查询方法 |
LinQ查询方法
获取数据:扩展方法Select()
- Select()是一个泛型扩展方法
- Select()方法使用的时候,要求传递一个委托实例(委托实例就是一个方法)
Select()方法应用
提示:数组、泛型集合都可以使用扩展方法Select()
筛选数据:Where()方法
- Where()方法是一个扩展泛型方法
- Where()方法使用的时候要求传递一个委托实例,但该实例是一个判断条件,因此返回的类型必须是bool类型
Where()方法应用
排序数据:OrderBy()
- OrderBy()是一个扩展方法
- OrderBy()里面的参数要求传递一个排序的字段,默认按照升序排列
- 如果想降序排列可以使用OrderByDescending方法
OrderBy()方法应用
分组数据:GroupBy()方法
- OrderBy()是一个扩展方法
- OrderBy()里面的参数要求传递一个分组的字段
GroupBy()方法应用
LinQ查询实际和查询形式
查询实际
观察如下代码的执行顺序
查询步骤
- 获取数据源、定义查询、执行查询
观察结论
- 定义查询后,查询并没有立即执行,而是直到需要枚举结果(遍历)时才被真正执行
- 这种方式称为“延迟执行(deferred execution)”
使用“聚合扩展方法”返回单一结果,强制查询立即执行
LINQ查询的两种形式
Method Syntax,查询方法方式
- 主要利用System.Linq.Enumerable类中定义的扩展方法和Lambda表达式方式进行查询
- 在此之前所用的查询都是这种方法
Query Syntax,查询语句方式
- 一种更接近SQL语法的查询方式,可读性更好
- 查询语句最后还是要被翻译成查询方法
LINQ查询子句概述
查询表达式
- 是一种用查询语法表示的表达式,由一组用类似于SQL的语法编写的句子组成
- 每一个子句可以包含一个或多个C#表达式
LINQ查询表达式包含的子句
- from子句:指定查询操作的数据源和范围变量
- where子句:筛选元素的逻辑条件,返回值是一个bool类型
- select子句:指定查询结果的类型和表现形式
- orderby子句:对查询结果进行排序(升序或降序)
- group子句:对查询结果进行分组
- into子句:提供一个临时标识符,该表示可充当对join/group/select子句结果的引用
- join子句:连接多个查询操作的数据源
- let子句:引入用于存储查询表达式中的子表达式结果的范围变量
from子句
from子句概述
- LINQ查询表达式必须包含from子句,并且必须以from子句开头
- from子句指定的数据源类型必须为IEnumerable、Ienumerable<T>或者两者的派生类型(例如:数组、 List<T>、ArrayList等)
关于数据源
- 如果数据源是泛型类型,则编译器可以自动推断出范围变量的类型,比如上面的num类型为int类型
- 如果数据源是非泛型类型,如ArrayList,则必须显示的指定范围变量的数据类型
复合from子句查询
- 如果数据源(本身是一个序列)的元素还包含子数据源(如序列、列表等),如果要查询子数据源中的元素,则需要使用复合from子句
多个from子句查询
- 若LINQ查询表达式包含两个或两个以上的独立数据源时,可以使用多个from子句查询所有数据源中的数据
其他常用子句
where子句概述
- 用于指定筛选元素的逻辑条件
- 一个查询表达式可以不包含where子句
- 如果查询表达式包含where子句,则where子句不能放在最后一个子句
select子句
- 用于指定查询结果的类型和表现形式
- LINQ查询表达式或者以select子句结束或者以group子句结束
group子句
- 用于对查询结果分组
- 返回元素类型为Igrouping<Tkey,TElement>对象序列
orderby子句
- 用于对查询结果排序,默认“升序”
- 在排序字段后面加上descending可以实现降序
其他子句:into/join/let(略)
LinQ高级查询
高级查询方法
聚合类
- Count , Max/Min , Average
排序类
- ThenBy
分区类
- Take , TakeWhile , Skip , SkipWhile
集合类
- Distinct
生成类
- Range, Repeat
聚合类查询
- Count返回集合项的数目
- Max/Min求最大值、最小值
- Average 返回集合的平均值
- Sum返回集合的总数
排序类
- ThenBy提供复合排序条件
分区类
- Take提取指定数量的项
- Skip跳过指定数量的项并获取剩余的项
- TakeWhile只要满足指定的条件,就会返回序列的元素,然后跳过剩余的元素
- SkipWhile只要满足指定的条件,就跳过序列中的元素,然后返回剩余元素
集合类查询Distinct
- Distinct去掉集合中的重复项
生成类查询
- Range生成一个整数序列
- Repeat生成一个重复项的序列
注意问题:
- Range/Repeat不是扩展方法,而是普通的静态方法
- Range只能产生整数序列
- Repeat可以产生泛型序列
- 所有的查询方法都存放在System.Linq.Enumerable 静态类中
示例
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 namespace LinqDemo 7 { 8 class Program 9 { 10 #region 示例1:不使用LINQ查询数组 11 static void Main(string[] args) 12 { 13 int[] nums = { 1, 7, 2, 6, 5, 4, 9, 13, 20 }; 14 List<int> list = new List<int>(); 15 foreach (int item in nums) 16 { 17 if (item % 2 != 0) 18 list.Add(item); 19 } 20 list.Sort(); 21 list.Reverse(); 22 foreach (int item in list) 23 { 24 Console.WriteLine(item); 25 } 26 Console.ReadLine(); 27 } 28 #endregion 29 #region 示例2:使用LINQ技术查询数组 30 //static void Main(string[] args) 31 //{ 32 // int[] nums = { 1, 7, 2, 6, 5, 4, 9, 13, 20 }; 33 // var list = from num in nums 34 // where num % 2 != 0 35 // orderby num descending 36 // select num; 37 // foreach (int item in list) 38 // { 39 // Console.WriteLine(item); 40 // } 41 // Console.ReadLine(); 42 //} 43 #endregion 44 #region 示例3:扩展方法Select()应用 45 //static void Main(string[] args) 46 //{ 47 // int[] nums = { 1, 7, 2, 6, 5, 4, 9, 13, 20 }; 48 // var list = nums.Select(item => item * item); 49 // foreach (int item in list) 50 // { 51 // Console.WriteLine(item); 52 // } 53 // Console.ReadLine(); 54 //} 55 #endregion 56 #region 示例4:扩展方法Where()应用 57 //static void Main(string[] args) 58 //{ 59 // int[] nums = { 1, 7, 2, 6, 5, 4, 9, 13, 20 }; 60 // var list = nums 61 // .Where(item => item % 2 == 0) 62 // .Select(i => i * i); 63 // Console.ReadLine(); 64 //} 65 #endregion 66 #region 示例5:扩展方法OrderBy()应用 67 //static void Main(string[] args) 68 //{ 69 // int[] nums = { 1, 7, 2, 6, 5, 4, 9, 13, 20 }; 70 // var list = nums 71 // .Where(item => item % 2 == 0) 72 // .Select(i => i * i) 73 // .OrderBy(item => item); 74 // foreach (int i in list) 75 // { 76 // Console.WriteLine(i); 77 // } 78 // Console.ReadLine(); 79 //} 80 //static void Main(string[] args) 81 //{ 82 // string[] nums = { "张勇", "王琦", "刘静", "赵鑫鑫", 83 // "杜丽", "马俊才", "那英", "成龙", }; 84 // var list = nums 85 // .Where(item => item.Length == 2) 86 // .Select(item => item) 87 // .OrderByDescending(item => item.Substring(0, 1)); 88 // foreach (string item in list) 89 // { 90 // Console.WriteLine(item); 91 // } 92 // Console.ReadLine(); 93 //} 94 #endregion 95 #region 示例6:扩展方法GroupBy()应用 96 //static void Main(string[] args) 97 //{ 98 // string[] nums = { "张勇", "王琦", "刘静", "赵鑫鑫", 99 // "杜丽", "马俊才", "那英", "成龙","王丽", "杜宇","马晓","刘丽","马大哈",}; 100 // var list = nums 101 // .Where(item => item.Length == 2) 102 // .Select(item => item) 103 // .GroupBy(item => item.Substring(0, 1)); 104 // foreach (var groupItem in list) 105 // { 106 // Console.WriteLine("-------------------"); 107 // Console.WriteLine("分组字段:{0}", groupItem.Key); 108 // foreach (var item in groupItem) 109 // { 110 // Console.WriteLine(item); 111 // } 112 // } 113 114 115 // Console.ReadLine(); 116 //} 117 #endregion 118 #region 示例7:断点调试LINQ的查询时机 119 //static void Main(string[] args) 120 //{ 121 // int[] nums = { 1, 7, 2, 6, 5, 4, 9, 13, 20 }; 122 // var list = nums 123 // .Where(item => item % 2 == 0) 124 // .Select(item => item * item) 125 // .OrderBy(item => item); 126 // foreach (int i in list) 127 // { 128 // Console.WriteLine(i); 129 // } 130 // Console.ReadLine(); 131 //} 132 #endregion 133 #region 示例8:查询的立即执行 134 //static void Main(string[] args) 135 //{ 136 // int[] nums = { 1, 7, 2, 6, 5, 4, 9, 13, 20 }; 137 // var list = nums 138 // .Where(item => item % 2 == 0) 139 // .Select(item => item * item) 140 // .OrderBy(item => item) 141 // .Count(); 142 // Console.WriteLine(list.ToString ()); 143 // Console.ReadLine(); 144 //} 145 #endregion 146 #region 示例9:from子句的简单使用 147 //static void Main(string[] args) 148 //{ 149 // ArrayList values = new ArrayList(); 150 // for (int i = 0; i < 10; i++) { values.Add(i); } 151 // var list = from int item in values 152 // where item % 2 == 0 153 // select item; 154 // foreach (int item in list) { Console.WriteLine(item); } 155 // Console.ReadLine(); 156 //} 157 #endregion 158 #region 示例10:复合from子句的使用 159 //static void Main(string[] args) 160 //{ 161 // Student obj1 = new Student() 162 // { 163 // StuId = 1001, 164 // StuName = "学员1", 165 // ScoreList = new List<int>() { 90, 78, 54 } 166 // }; 167 // Student obj2 = new Student() 168 // { 169 // StuId = 1002, 170 // StuName = "学员2", 171 // ScoreList = new List<int>() { 95, 88, 90 } 172 // }; 173 // Student obj3 = new Student() 174 // { 175 // StuId = 1003, 176 // StuName = "学员3", 177 // ScoreList = new List<int>() { 79, 76, 89 } 178 // }; 179 // //将学员封装到集合中 180 // List<Student> stuList = new List<Student>() { obj1, obj2, obj3 }; 181 // //查询成绩包含95分以上的学员 182 // var result = from stu in stuList 183 // from score in stu.ScoreList 184 // where score >= 95 185 // select stu; 186 // //显示查询结果 187 // foreach (var item in result) 188 // { 189 // Console.WriteLine(item.StuName); 190 // } 191 192 // Console.ReadLine(); 193 //} 194 #endregion 195 #region 示例11:多个from子句查询的使用 196 //static void Main(string[] args) 197 //{ 198 // Student obj1 = new Student() { StuId = 1001, StuName = "学员1" }; 199 // Student obj2 = new Student() { StuId = 1009, StuName = "学员9" }; 200 // Student obj3 = new Student() { StuId = 1012, StuName = "学员12" }; 201 // Student obj4 = new Student() { StuId = 1003, StuName = "学员3" }; 202 // Student obj5 = new Student() { StuId = 1019, StuName = "学员19" }; 203 // Student obj6 = new Student() { StuId = 1006, StuName = "学员6" }; 204 // List<Student> stuList1 = new List<Student>() { obj1, obj2, obj3 }; 205 // List<Student> stuList2 = new List<Student>() { obj4, obj5, obj6 }; 206 // //查询学好大于1010的学员 207 // var result = from stu1 in stuList1 208 // where stu1.StuId >= 1010 209 // from stu2 in stuList2 210 // where stu2.StuId >= 1010 211 // select new { stu1, stu2 }; 212 // //显示查询结果 213 // foreach (var item in result ) 214 // { 215 // Console.WriteLine(item.stu1.StuName+" "+item.stu1.StuId); 216 // Console.WriteLine(item.stu2.StuName + " " + item.stu2.StuId); 217 // } 218 // Console.ReadLine(); 219 //} 220 #endregion 221 #region 示例12:聚合函数Count 222 //static void Main(string[] args) 223 //{ 224 // Student obj1 = new Student() { StuId = 1001, StuName = "学员1" }; 225 // Student obj2 = new Student() { StuId = 1009, StuName = "学员9" }; 226 // Student obj3 = new Student() { StuId = 1012, StuName = "学员12" }; 227 // Student obj4 = new Student() { StuId = 1003, StuName = "学员3" }; 228 // Student obj5 = new Student() { StuId = 1019, StuName = "学员19" }; 229 // Student obj6 = new Student() { StuId = 1006, StuName = "学员6" }; 230 // List<Student> stuList = new List<Student>() { obj1, obj2, obj3, obj4, obj5, obj6 }; 231 // var count1 = (from c in stuList 232 // where c.StuId > 1010 233 // select c).Count(); 234 // var count2 = stuList.Where(c => c.StuId > 1010).Count(); 235 // Console.WriteLine("count1={0} count2={1}",count1,count2); 236 237 // Console.ReadLine(); 238 //} 239 #endregion 240 #region 示例13:聚合函数Max、Min、Average 241 //static void Main(string[] args) 242 //{ 243 // Student obj1 = new Student() { StuId = 1001, Age = 22, StuName = "学员1" }; 244 // Student obj2 = new Student() { StuId = 1009, Age = 21, StuName = "学员9" }; 245 // Student obj3 = new Student() { StuId = 1012, Age = 25, StuName = "学员12" }; 246 // Student obj4 = new Student() { StuId = 1003, Age = 23, StuName = "学员3" }; 247 // Student obj5 = new Student() { StuId = 1019, Age = 27, StuName = "学员19" }; 248 // Student obj6 = new Student() { StuId = 1006, Age = 24, StuName = "学员6" }; 249 // List<Student> stuList = new List<Student>() { obj1, obj2, obj3, obj4, obj5, obj6 }; 250 // var maxAge = (from s in stuList 251 // select s.Age).Max(); 252 // var minAge = stuList 253 // .Select(s => s.Age).Min(); 254 // var avgAge = (from s in stuList 255 // select s.Age).Average(); 256 // var sumAge = (from s in stuList 257 // select s.Age).Sum(); 258 // Console.WriteLine("maxAge={0} minAge={1} avgAge={2} sumAge={3}", 259 // maxAge, minAge, avgAge,sumAge); 260 // Console.ReadLine(); 261 //} 262 #endregion 263 #region 示例14:排序类ThenBy的使用 264 //static void Main(string[] args) 265 //{ 266 // Student obj1 = new Student() { StuId = 1001, Age = 22, StuName = "学员1" }; 267 // Student obj2 = new Student() { StuId = 1009, Age = 21, StuName = "学员9" }; 268 // Student obj3 = new Student() { StuId = 1012, Age = 25, StuName = "学员12" }; 269 // Student obj4 = new Student() { StuId = 1003, Age = 23, StuName = "学员3" }; 270 // Student obj5 = new Student() { StuId = 1019, Age = 27, StuName = "学员19" }; 271 // Student obj6 = new Student() { StuId = 1006, Age = 24, StuName = "学员6" }; 272 // List<Student> stuList = new List<Student>() { obj1, obj2, obj3, obj4, obj5, obj6 }; 273 // var stus1 = from s in stuList 274 // orderby s.StuName, s.Age, s.StuId 275 // select s; 276 // var stus2 = stuList 277 // .OrderBy(s => s.StuName) 278 // .ThenBy(s => s.Age) 279 // .ThenBy(s => s.StuId) 280 // .Select(p => p); 281 // foreach (var s in stus1) 282 // { 283 // Console.WriteLine(s.StuName); 284 // } 285 // Console.WriteLine("----------------------"); 286 // foreach (var s in stus2) 287 // { 288 // Console.WriteLine(s.StuName); 289 // } 290 // Console.ReadLine(); 291 //} 292 #endregion 293 #region 示例15:分区类查询 294 //static void Main(string[] args) 295 //{ 296 // int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 297 // var list1 = nums.Skip(1).Take(3); 298 // var list2 = nums.SkipWhile(i => i % 3 != 0) 299 // .TakeWhile(i => i % 2 != 0); 300 // foreach (var item in list1) { Console.WriteLine(item); } 301 // Console.WriteLine("------------"); 302 // foreach (var item in list2) { Console.WriteLine(item); } 303 // Console.ReadLine(); 304 //} 305 #endregion 306 #region 示例16:集合类查询Distinct 307 //static void Main(string[] args) 308 //{ 309 // int[] nums = { 1, 2, 2, 6, 5, 6, 7, 8, 8 }; 310 // var list = nums.Distinct(); 311 // foreach (var item in list) { Console.WriteLine(item); } 312 // Console.ReadLine(); 313 //} 314 #endregion 315 #region 示例17:生成类查询 316 //static void Main(string[] args) 317 //{ 318 //var nums1 = Enumerable.Range(1, 10); 319 // var nums2 = Enumerable.Repeat("LINQ best!", 10); 320 // foreach (var item in nums1) { Console.WriteLine(item); } 321 // Console.WriteLine("------------"); 322 // foreach (var item in nums2) { Console.WriteLine(item); } 323 324 // Console.ReadLine(); 325 //} 326 #endregion 327 } 328 }
END