linq总结系列(一)---基础部分
一、linq的基本概念
LINQ是C#和VB中的统一查询语法,使用对象来保存和检索来自不同来源(如数据库、xml、对象集合)的数据。
主要功能:消除了编程语言和数据库之间的不匹配,以及为不同类型的数据源提供统一的查询接口。
适用范围:LInq适用于实现了IEnumerable <T>(IQueryable继承于IEnumerable )的实例,如:List,Dictionary,Queue,LinkedList,Array等
二、linq的使用
有两种方法可以将LINQ查询写入IEnumerable集合或IQueryable数据源。
1、查询语法
特点:以from子句开头,可以以select或groupBy子句结束
2、lambda表达式(简洁且功能更多,推荐)
下边给出了简单的例子,注:后边的部分都是使用的这个测试数据。
1 //准备的测试数据 2 IList<UserInfo> userList = new List<UserInfo>() { 3 new UserInfo() { UId = 1, UserName = "zs", Age = 23 ,RoleId=1} , 4 new UserInfo() { UId = 2, UserName = "ls", Age = 20 ,RoleId=2}, 5 new UserInfo() { UId = 3, UserName = "ww", Age = 33 ,RoleId=1}, 6 new UserInfo() { UId = 4, UserName = "zl", Age = 26 ,RoleId=2}, 7 new UserInfo() { UId = 5, UserName = "tq", Age = 42 ,RoleId=2} 8 };//用户列表 9 IList<RoleInfo> roleList = new List<RoleInfo>(){ 10 new RoleInfo(){Rid=1,RoleName="管理员"}, 11 new RoleInfo(){Rid=2,RoleName="普通用户"}, 12 };//角色列表 13 14 //query语法 15 var resUsers = from u in userList 16 where u.Age > 20 17 select new {u.UId,u.UserName,u.Age}; 18 //lambda 19 var resUsers2 = userList.Where<UserInfo>(u => u.Age > 20).Select
(u => new { u.UId,u.UserName,u.Age});
三、linq详解
1、过滤 (where 和 oftype)
Where:根据给定的条件表达式过滤集合,并返回一个新集合
OfType:根据类型进行过滤
1 IList<object> list = new List<object>() { 1, "hello", user };//user是一个UserInfo的实例 2 //query语法 3 var result = from o in list.OfType<string>() 4 select o; 5 //lambda语法 6 var result2 = list.OfType<string>();
2、排序(OrderBy,OrderByDescending,ThenBy,ThenByDescending)
1 //对userList先按Id排序,再按Age排序 2 //query语法 3 var result = from u in userList 4 orderby u.Id,u.Age descending 5 select u; 6 //lambda语法 7 var result2 = userList.OrderByDescending(u => u.Id).ThenBy(u=>u.Age);
3、分组(group by,ToLookUp)
//query语法 var resGroups = from u in userList group u by u.RoleId; //lambda方式 注:GroupBy延迟执行,而ToLookup是立即执行的,使用方法和GroupBy一样。 var resGroups2 = userList.GroupBy(u => u.RoleId); //遍历(group.Key为设置分组的列的值) foreach (var group in resGroups) { Console.WriteLine("roleId:{0}", group.Key); foreach (UserInfo user in group) { Console.WriteLine("UserName:{0}", user.UserName); } } /*结果: roleId:1 UserName:zs UserName:ww roleId:2 UserName:ls UserName:zl 21 UserName:tq */ //多列分组 var productGroup= from p in db.Products group p by new { p.PName, p.PColor } into g select new { g.Key,//这里的key是一个对象,有两个属性:PName,PColor g };
4、连接查询(join)
//query语法,查询用户名和该用户所属的角色 inner join var resJoin = from user in userList join role in roleList on user.RoleId equals role.Rid select new { uname=user.UserName, rname=role.RoleName }; //left join,right join调整下顺序即可 var resJoin = from user in userList join role in roleList on user.RoleId equals role.Rid into temp from tt in temp.DefaultIfEmpty select new { uname=user.UserName, rname=role?.RoleName }; //cross join var resJoin = from user in userList from role in roleList select new { uname=user?.UserName, rname=role?.RoleName }; //lambda方式 var resJoin2 = userList.Join(roleList, user => user.RoleId, //outkey role => role.Rid, //innerkey (user, role) => new //result { uname = user.UserName, rname = role.RoleName }); //遍历 foreach (var item in resJoin2) { Console.WriteLine("用户:{0}----角色:{1}", item.uname, item.rname); } /*结果: 用户:zs----角色:管理员 用户:ls----角色:普通用户 用户:ww----角色:管理员 用户:zl----角色:普通用户 用户:tq----角色:普通用户 */
5、linq中的量词(All,Any,Contains)
1 //All 所有元素都符合条件返回true 2 bool areAllAdmin = userList.All(u => u.RoleId == 1); //所有用户的roleid都是1--->false 3 //Any 有一个符合条件就返回true 4 bool isAnyAdmin = userList.Any(u => u.RoleId == 1);//用户里有没有roleid为1的 --> true 5 //Contains 包含返回true 6 UserInfo user1=new UserInfo() { UId = 1, UserName = "zs", Age = 23, RoleId = 1 }; 7 //contains比较的是索引,所以就是list中有一个属性都相同的元素也会返回false,我们可以自定义一个比较类CompareUser来解决这个问题 8 bool isContains = userList.Contains(user1);//s索引不同:false 9 bool isContains2=userList.Contains(user1,new CompareUser());//自定义比较:true 10 11 //自定义的userinfo比较器 12 public class CompareUser : IEqualityComparer<UserInfo> 13 { 14 public bool Equals(UserInfo x, UserInfo y) 15 { 16 bool isSame = false; 17 //age,username,roleid相同,我们就认为是同一个userinfo 18 if (x.Age==y.Age&&x.UserName==y.UserName&&x.RoleId==y.RoleId) 19 { 20 isSame=true; 21 } 22 return isSame; 23 } 24 public int GetHashCode(UserInfo obj) 25 { 26 throw new NotImplementedException(); 27 } 28 }
6、聚合函数(Average,Count,Max,Min,Sum)
1 //平均年龄:28.8 2 var avgAge = userList.Average(u => u.Age); 3 //用户人数:5: 大于30岁的用户人数:2 4 var userCount = userList.Count(); 5 var olduserCount = userList.Count(u => u.Age > 30); 6 //最大年龄:42 7 var maxAge = userList.Max(u => u.Age); 8 //最小年龄:20 9 var minAge = userList.Min(u => u.Age); 10 //年龄和:144 11 var sumAge = userList.Sum(u => u.Age);
7、元素操作符(ElementAt,Frist,Last,Singe和对应的xxxOrDefault)
这些操作符加上OrDefault后缀后,在超出索引时不会抛出异常,而是返回一个默认值,(如:int返回0 ,引用类型返回null)
1 //获取指定索引处的元素 2 UserInfo user0 = userList.ElementAt(0); 3 UserInfo user9 = userList.ElementAtOrDefault(9); 4 //不报错,返回null,没有ordefault后缀会抛异常 5 //获取第一个元素 6 UserInfo userfrist = userList.First(); 7 UserInfo userfrist2 = userList.FirstOrDefault(); 8 //获取最后一个元素 9 UserInfo userlast = userList.Last(); 10 UserInfo userlast2 = userList.LastOrDefault(); 11 //获取唯一元素() 12 UserInfo userSignal = userList.Single(u => u.Age < 21); 13 UserInfo userSignal2 = userList.SingleOrDefault(u => u.Age > 21);
//报错,返回的元素不是唯一的
8、判断序列相等(SequenceEqual)
1 //原始类型(字符串、int等,比较顺序和值,这两项都相等时返回true) 2 IList<int> intList1 = new List<int> { 1, 2, 3, 4 }; 3 IList<int> intList2 = new List<int> { 2, 1, 3, 4 }; 4 //bool isEquel = intList1.SequenceEqual(intList2); 5 6 //复杂类型(UserInfo,比较索引,索引相同返回true,可通过自定义比较器修改比较的规则) 7 UserInfo user1 = new UserInfo() { UId = 1, UserName = "zs", Age = 23, RoleId = 1 }; 8 UserInfo user2 = new UserInfo() { UId = 1, UserName = "zs", Age = 23, RoleId = 1 }; 9 IList<UserInfo> list1 = new List<UserInfo>() { user1 }; 10 IList<UserInfo> list2 = new List<UserInfo>() { user2}; 11 //user1和user2的索引不同,返回false 12 bool isEquel = list1.SequenceEqual(list2); 13 //自定义比较器,只要属性都相等返回true 14 bool isEquel2 = list1.SequenceEqual(list2, new CompareUser()); 15 16 17 //自定义的userinfo比较器 18 public class CompareUser : IEqualityComparer<UserInfo> 19 { 20 public bool Equals(UserInfo x, UserInfo y) 21 { 22 bool isSame = false; 23 //age,username,roleid相同,我们就认为是同一个userinfo 24 if (x.Age==y.Age&&x.UserName==y.UserName&&x.RoleId==y.RoleId) 25 { 26 isSame=true; 27 } 28 return isSame; 29 } 30 public int GetHashCode(UserInfo obj) 31 { 32 throw new NotImplementedException(); 33 } 34 }
9、集合操作(Concat、Distinct、Except、Intersect、Union)
1 //合并 Concat 2 IList<UserInfo> list1 = new List<UserInfo>() { user1,user2,user1 }; 3 IList<UserInfo> list2 = new List<UserInfo>() { user2 ,user2}; 4 var listConcat = list1.Concat(list2);
//包含了user1,user2,user1,user2,user2 5 //去重 Distinct(差并交集会自动去重,去重和交差并集中的复杂类型也是根据索引来判断是否相同的,所以视情况自定义比较器) 6 var list4 = list1.Distinct();//user1,user2 7 //差集(list1中有,list中没有的) 8 var list5 = list1.Except(list2);//user1 9 //交集 10 var list6 = list1.Intersect(list2);//user2 11 //并集 12 var list7 = list1.Union(list2);//user1,user2
10、分区(Skip,SkipWhile,Take,TakeWhile)
1 //分区 2 var resUsers = userList.Skip(2);//跳过前2条,返回从第3条到最后一条的记录 3 var resUsers2 = userList.SkipWhile(u => u.Age < 30); // 跳过满足条件的数据 4 //结果:从年龄为33的开始,返回后几条 5 6 var resTake = userList.Take(2);//取前2条数据 7 var resTake2 = userList.TakeWhile(u => u.Age >= 22); 8 //取满足条件的数据,如果连续几条都满足返回多条记录,直到某一条数据不满足条件 9 //结果:返回第一条,如果把条件中22改成20,那么返回所有数据
11、类型转化(As,To,Cast) select 默认返回的是IEnumerable类型
1 var users = from u in userList select u; //IEnumerable<UserInfo> 2 var usersEnum = (from u in userList select u).AsEnumerable<UserInfo>();//IEnumerable<UserInfo> 3 var usersCast = (from u in userList select u).Cast<UserInfo>();//IEnumerable<UserInfo>,功能和AsEnumerable一样,写着简单 4 var usersQuery = (from u in userList select u).AsQueryable<UserInfo>();//IQueryable<UserInfo> 5 var usersArray = (from u in userList select u).ToArray<UserInfo>();//UserInfo[] 6 var usersList = (from u in userList select u).ToList<UserInfo>();//List<UserInfo> 7 var usersDic = (from u in userList select u).ToDictionary<UserInfo,int>(u=>u.UId);//Dictionary<int,UserInfo>