第十三节:Lambda、linq、SQL的相爱相杀(2)
一. Linq开篇
1.Where用法
linq中where的用法与SQL中where的用法基本一致。
1 #region 01-where用法 2 { 3 //1. where用法 4 //1.1 查询账号为admin的用户信息 5 Console.WriteLine("---------------------------- 1. where用法 ----------------------------------------"); 6 Console.WriteLine("---------------------------- 1.1 查询账号为admin的用户信息 ----------------------------------------"); 7 List<Sys_UserInfor> sUserList1 = (from u in db.Sys_UserInfor 8 where u.userAccount == "admin" 9 select u).ToList(); 10 11 foreach (var item in sUserList1) 12 { 13 Console.WriteLine("用户名:{0},用户账号:{1},用户年龄:{2},用户性别:{3}", item.userName, item.userAccount, item.userAge, item.userSex); 14 } 15 //1.2 查询账号为中包含admin且性别为男的用户信息 16 Console.WriteLine("---------------------------- 1.2 查询账号为中包含admin且性别为男的用户信息 ----------------------------------------"); 17 List<Sys_UserInfor> sUserList2 = (from u in db.Sys_UserInfor 18 where u.userAccount.Contains("admin") && u.userSex == "男" 19 select u).ToList(); 20 foreach (var item in sUserList2) 21 { 22 Console.WriteLine("用户名:{0},用户账号:{1},用户年龄:{2},用户性别:{3}", item.userName, item.userAccount, item.userAge, item.userSex); 23 } 24 } 25 #endregion
2.Select用法
与前一个章节lambda中介绍的一样,select可以全部查询或查询部分字段。
查询部分的时候可以使用匿名类或者实体类,使用匿名的时候也可以指定列名。
1 #region 02-select用法 (匿名类和非匿名类写法) 2 { 3 //2. select用法 (匿名类和非匿名类写法) 4 //2.1 查询账号中包含 admin 的用户的 姓名、年龄和性别 三条信息 (匿名类的写法,自动生成匿名类名称) 5 Console.WriteLine("---------------------------- 2. select用法 (匿名类和非匿名类写法) ----------------------------------------"); 6 Console.WriteLine("-------------2.1 查询账号中包含 admin 的用户的 姓名、年龄和性别 三条信息 (匿名类的写法)-------------------------"); 7 var sUserList1 = (from u in db.Sys_UserInfor 8 where u.userAccount.Contains("admin") 9 select new 10 { 11 u.userName, 12 u.userAge, 13 u.userSex 14 }).ToList(); 15 sUserList1.ForEach(u => 16 { 17 Console.WriteLine("用户名:{0},用户年龄:{1},用户性别:{2}", u.userName, u.userAge, u.userSex); 18 }); 19 //2.2 查询账号中包含 admin 的用户的 姓名、年龄和性别 三条信息 (匿名类的写法,指定匿名类名称) 20 Console.WriteLine("---------2.2 查询账号中包含 admin 的用户的 姓名、年龄和性别 三条信息 (匿名类的写法 指定匿名类名称)--------"); 21 var sUserList2 = (from u in db.Sys_UserInfor 22 where u.userAccount.Contains("admin") 23 select new 24 { 25 Name = u.userName, 26 Age = u.userAge, 27 Sex = u.userSex 28 }).ToList(); 29 sUserList2.ForEach(u => 30 { 31 Console.WriteLine("用户名:{0},用户年龄:{1},用户性别:{2}", u.Name, u.Age, u.Sex); 32 }); 33 //2.3 查询账号中包含 admin 的用户的 姓名、年龄和性别 三条信息 (非匿名类的写法) 34 Console.WriteLine("-------------2.3 查询账号中包含 admin 的用户的 姓名、年龄和性别 三条信息 (非匿名类的写法)-------------------------"); 35 List<newUserInfor> sUserList3 = (from u in db.Sys_UserInfor 36 where u.userAccount.Contains("admin") 37 select new newUserInfor 38 { 39 newName = u.userName, 40 newAge = u.userAge, 41 newSex = u.userSex 42 }).ToList(); 43 sUserList3.ForEach(u => 44 { 45 Console.WriteLine("用户名:{0},用户年龄:{1},用户性别:{2}", u.newName, u.newAge, u.newSex); 46 }); 47 } 48 #endregion
3.orderby用法
关键字是:orderby (默认是升序) 和orderby descending
需要按照多个条件进行升序或降序,格式为: orderby x1,x2 descending,x3 (表示先按照x1升序排,x1相同的话,再按照x2降序排,x2相同的话,在按照x3升序排列)
1 #region 03-orderby用法 2 { 3 //区分:在Lambda中有 orderby(OrderByDescending、ThenBy、ThenByDescending),但在Linq中 只有orderby (默认是升序) 和orderby descending 4 //需要按照多个条件进行升序或降序,格式为: orderby x1,x2 descending,x3 (表示先按照x1升序排,x1相同的话,再按照x2降序排,x2相同的话,在按照x3升序排列) 5 //3. OrderBy用法 (单条件升降序、多条件综合排序) 6 //3.1 查询delflag 为1 的所有用户信息,按照时间升序排列 7 Console.WriteLine("------3. orderby用法 (单条件升降序、多条件综合排序)-------------"); 8 Console.WriteLine("--------------------- 3.1 查询delflag 为1 的所有用户信息,按照时间升序排列 ------------------------------"); 9 List<Sys_UserInfor> sUserList1 = (from u in db.Sys_UserInfor 10 where u.delFlag == 1 11 orderby u.addTime 12 select u).ToList(); 13 foreach (var item in sUserList1) 14 { 15 Console.WriteLine("用户名:{0},用户账号:{1},用户年龄:{2},用户性别:{3},创建时间:{4}", item.userName, item.userAccount, item.userAge, item.userSex, item.addTime); 16 } 17 //3.2 查询delflag 为1 的所有用户信息,先按照时间升序排列,再按照年龄降序 18 Console.WriteLine("---------------3.2 查询delflag 为1 的所有用户信息,先按照时间升序排列,再按照年龄降序----------------------"); 19 List<Sys_UserInfor> sUserList2 = (from u in db.Sys_UserInfor 20 where u.delFlag == 1 21 orderby u.addTime, u.userAge descending 22 select u).ToList(); 23 foreach (var item in sUserList2) 24 { 25 Console.WriteLine("用户名:{0},用户账号:{1},用户年龄:{2},用户性别:{3},创建时间:{4}", item.userName, item.userAccount, item.userAge, item.userSex, item.addTime); 26 } 27 } 28 #endregion
4.多表关联查询
用到的用户表和用户登录记录表如下:
这里类比SQL语句里的查询,查询包括内连接和外连接,其中,
1.内连接分为:隐式内连接和显示内连接. 特点:二者只是写法不同,查询出来的结果都是多表交叉共有的。
(1).隐式内连接: 多个from并联拼接
(2).显示内连接: join-in-on拼接,注意没有into哦!加上into就成外连接了。
PS:这里的内连接相当于sql中的等值连接inner join。
2.外连接分为:左外连接和右外连接.
(1).左外连接:查询出JOIN左边表的全部数据,JOIN右边的表不匹配的数据用NULL来填充。
(2).右外连接:查询出JOIN右边表的全部数据,JOIN左边的表不匹配的数据用NULL来填充。
PS:linq中没有sql中的left/right join, 只有join,左外连接和右外连接通过颠倒数据的顺序来实现。
注:外连接join后必须有into,然后可以加上XX.DefaultIfEmpty(),表示对于引用类型将返回null,而对于值类型则返回0。对于结构体类型,则会根据其成员类型将它们相应地初始化为null(引用类型)或0(值类型)
3. 分析几个场景,一对一,一对多,而且还要统计个数的案例
(1).用户表-用户详情表(一对一):用内连接
(2).用户表-用户登录记录表(一对零,一对多):用左外连接,用户表为左,如果统计个数需要用Distinct()去重.
1 //4.查询账号中含有admin的所有用户的用户昵称、账号、和登录信息 2 //4.1 隐式内连接(匿名类且不指定名称) 3 Console.WriteLine("---------------04-多表关联查询--------------------"); 4 Console.WriteLine("---------------4.1 隐式内连接(匿名类且不指定名称)--------------------"); 5 var uList1 = (from a in db.Sys_UserInfor 6 from b in db.LoginRecords 7 where a.id == b.userId 8 select new 9 { 10 a.userName, 11 a.userAccount, 12 b.loginCity, 13 b.loginIp, 14 b.loginTime 15 }).ToList(); 16 foreach (var item in uList1) 17 { 18 Console.WriteLine("姓名:{0},账号:{1},登录城市:{2},登录IP:{3},登录时间:{4}", item.userName, item.userAccount, item.loginCity, item.loginIp, item.loginTime); 19 } 20 //4.2 显式内链接(匿名类 且部分列指定名称) 21 Console.WriteLine("---------------4.2 显式内链接(匿名类 且部分列指定名称) --------------------"); 22 var uList2 = (from a in db.Sys_UserInfor 23 join b in db.LoginRecords on a.id equals b.userId 24 select new 25 { 26 UserName = a.userName, 27 UserAccount = a.userAccount, 28 b.loginCity, 29 b.loginIp, 30 b.loginTime 31 }).ToList(); 32 foreach (var item in uList2) 33 { 34 Console.WriteLine("姓名:{0},账号:{1},登录城市:{2},登录IP:{3},登录时间:{4}", item.UserName, item.UserAccount, item.loginCity, item.loginIp, item.loginTime); 35 } 36 //4.3 查询所有用户的登录信息(左外连接的方式) 37 //join时必须将join后的表into到一个新的变量XX中,然后要用XX.DefaultIfEmpty()表示外连接。 38 //DefaultIfEmpty使用了泛型中的default关键字。default关键字对于引用类型将返回null,而对于值类型则返回0。对于结构体类型,则会根据其成员类型将它们相应地初始化为null(引用类型)或0(值类型) 39 Console.WriteLine("-----------------------4.3 查询所有用户的登录信息(左外连接的方式)----------------------------"); 40 var uList3 = (from a in db.Sys_UserInfor 41 join b in db.LoginRecords on a.id equals b.userId into fk 42 from c in fk.DefaultIfEmpty() 43 select new 44 { 45 UserName = a.userName, 46 UserAccount = a.userAccount, 47 c.loginCity, 48 c.loginIp, 49 c.loginTime 50 }).ToList(); 51 foreach (var item in uList3) 52 { 53 Console.WriteLine("姓名:{0},账号:{1},登录城市:{2},登录IP:{3},登录时间:{4}", item.UserName, item.UserAccount, item.loginCity, item.loginIp, item.loginTime); 54 } 55 // 4.4 查询所有用户的登录信息(右外连接的方式) 56 Console.WriteLine("-----------------------4.4 查询所有用户的登录信息(右外连接的方式)----------------------------"); 57 var uList4 = (from a in db.LoginRecords 58 join b in db.Sys_UserInfor on a.userId equals b.id into fk 59 from c in fk.DefaultIfEmpty() 60 select new 61 { 62 UserName = c.userName, 63 UserAccount = c.userAccount, 64 a.loginCity, 65 a.loginIp, 66 a.loginTime 67 }).ToList(); 68 foreach (var item in uList4) 69 { 70 Console.WriteLine("姓名:{0},账号:{1},登录城市:{2},登录IP:{3},登录时间:{4}", item.UserName, item.UserAccount, item.loginCity, item.loginIp, item.loginTime); 71 } 72 //4.5 查询每个用户的登录次数(用且应该用左外连接 ) 73 //注:这里需要加一个Distinct()去重,否则同一个账号会查出来多条数据重复了 74 Console.WriteLine("-----------------------4.5 查询每个用户的登录次数(用且应该用左外连接 )----------------------------"); 75 var uList5 = (from a in db.Sys_UserInfor 76 join b in db.LoginRecords on a.id equals b.userId into fk 77 select new 78 { 79 UserName = a.userName, 80 UserAccount = a.userAccount, 81 loginCount = fk.Count() 82 }).Distinct().ToList(); 83 foreach (var item in uList5) 84 { 85 Console.WriteLine($"姓名:{item.UserName},账号:{item.UserAccount},登录次数:{item.loginCount}"); 86 }
运行 结果:
5. group by into 分组
1 #region 05-group By分组(匿名类写法) 2 { 3 //5. GroupBy分组(需要重点看一下) 4 //5.1 根据用户的性别进行分类,然后将不同性别的用户信息输出来 5 Console.WriteLine("-------------------- 5. GroupBy分组------------------------"); 6 Console.WriteLine("-------------------- 5.1 根据用户的性别进行分类,然后将不同性别的用户信息输出来------------------------"); 7 var sUserListGroup = (from u in db.Sys_UserInfor 8 group u by u.userSex into fk 9 select fk).ToList(); 10 foreach (var group in sUserListGroup) 11 { 12 Console.WriteLine("性别为:{0}", group.Key); //分组依据的字段内容 13 foreach (var item in group) 14 { 15 Console.WriteLine("用户名:{0},用户账号:{1},用户年龄:{2},用户性别:{3}", item.userName, item.userAccount, item.userAge, item.userSex); 16 } 17 } 18 //5.2 根据用户性别进行分类,然后将不同性别的年龄大于等于21岁的用户信息输出来 19 Console.WriteLine("-------------5.2 根据用户性别进行分类,然后将不同性别的年龄大于等于21岁的用户信息输出来-------------------"); 20 var sUserListGroup2 = (from u in db.Sys_UserInfor 21 where u.userAge >= 21 22 group u by u.userSex into fk 23 select fk).ToList(); 24 foreach (var group in sUserListGroup2) 25 { 26 Console.WriteLine("性别为:{0}", group.Key); //分组依据的字段内容 27 foreach (var item in group) 28 { 29 Console.WriteLine("用户名:{0},用户账号:{1},用户年龄:{2},用户性别:{3}", item.userName, item.userAccount, item.userAge, item.userSex); 30 } 31 } 32 } 33 #endregion
6. skip和take用法
1 #region 06-Skip和Take用法 2 { 3 4 //6. Skip和Take 分页用法 5 //skip表示跳过多少条,Take表示取多少条 6 //6.1 根据时间降序排列,取第2和第3条数据(即先排序,然后跨过1条,取2条数据) 7 Console.WriteLine("--------------------6. Skip和Take 分页用法------------------------"); 8 Console.WriteLine("---------6.1 根据时间降序排列,取用户信息中的第2和第3条数据(即先排序,然后跨过1条,取2条数据)---------"); 9 var sUserList = (from u in db.Sys_UserInfor 10 orderby u.addTime descending 11 select u).Skip(1).Take(2).ToList(); 12 sUserList.ForEach(u => 13 { 14 Console.WriteLine("用户名:{0},用户年龄:{1},用户性别:{2},创建时间:{3}", u.userName, u.userAge, u.userSex, u.addTime); 15 }); 16 } 17 #endregion
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。