一、查询数据源
1.查询数组
#region 查询数组
int[] num = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };//查询数组
//在传统开发过程中,如果需要筛选大于5的数据,则需要遍历整个数组进行比较,代码如下:
for (int i = 0; i < num.Length; i++)
{
if (num[i] > 5)
{
Console.WriteLine(num[i].ToString());
}
}
Console.ReadLine();
//上述代码虽然实现了功能要求,但是这样编写的代码不具扩展性而且还需要进行数组遍历
//如果使用LINQ查询语句进行查询就非常简单,代码如下:
var numResult = from data in num where data > 5 select data;
foreach (var i in numResult)
{
Console.WriteLine(i.ToString());
}
Console.ReadLine();
string[] str = { "我爱C#", ".NET编程", "辣鸡", "WebService", "C#6.0" };
//对于一个字符串数组,如果要查询包含"C#"的字符串,对于传统的变成方法是非常冗余和繁琐的。
//但使用LINQ就非常简单,代码如下:
var strResult = from data in str where data.Contains("C#") select data;
#endregion
2.查询数据库
#region 查询数据库
booksDataContext books = new booksDataContext();
var bookResult = from book in books.Books
from sell in books.Sell
where book.BookId == sell.BookId && sell.SellCount > 200
select book;
foreach (var item in bookResult)
{
Console.WriteLine(item.BookName.ToString());
}
Console.ReadLine();
#endregion
二、LINQ基本子句
1.from子句嵌套查询
#region from子句嵌套查询
List<string> name = new List<string>();
name.Add("liyang");
name.Add("zhangmengjie");
name.Add("zhangyufeng");
name.Add("gaoqun");
name.Add("zhangjiale");
name.Add("zhanghaotian");
List<string> email = new List<string>();
email.Add("liyang@qq.com");
email.Add("zhangmengjie@qq.com");
email.Add("zhangyufengzhangyufeng@qq.com");
email.Add("gaoqun@qq.com");
email.Add("zhangjiale@qq.com");
email.Add("zhanghaotian@qq.com");
var nameResult = from namedata in name
from emaildata in email
where emaildata.Contains(namedata)
select namedata;
foreach (var item in nameResult)
{
Console.WriteLine(item);
}
Console.ReadLine();
#endregion
2.select选择子句查询
#region select选择子句查询
var emailResult = from namedata in name
from emaildata in email
where emaildata.Contains(namedata)
select emaildata;
foreach (var item in emailResult)
{
Console.WriteLine(item);
}
Console.ReadLine();
#endregion
3.orderby排序子句
#region orderby排序子句
//升序ascending 降序descending
var paixuResult = from data in num
where data > 5
orderby data descending //降序 orderby子句中可以有多个条件,多个条件用","分割
select data;
foreach (var item in paixuResult)
{
Console.WriteLine(item.ToString());
}
Console.ReadLine();
#endregion
4.group分组子句
#region group分组子句
//group子句返回的元素类型是IGrouping<TKey,TElement>的对象序列,必须在一个循环中嵌套一个对象的循环才能够查询相应的数据元素
//在使用group子句时,LINQ查询子句的末尾并没有select子句
List<Student> person = new List<Student>();
person.Add(new Student(1, 25, "李阳"));
person.Add(new Student(2, 26, "张梦洁"));
person.Add(new Student(3, 18, "张玉峰"));
person.Add(new Student(4, 18, "高群"));
person.Add(new Student(5, 19, "张浩天"));
person.Add(new Student(6, 16, "张佳乐"));
var personResult = from per in person
orderby per.Age ascending
group per by per.Age; //??没有select
foreach (var item in personResult)
{
Console.WriteLine(item.Key + "岁组里的学生有:");
foreach (Student s in item)
{
Console.WriteLine(s.Name);
}
}
Console.ReadLine();
#endregion
5.into联接子句
#region into联接子句
//into子句通常需要与group子句一起使用,且必须放在以select、groupby等子句作为结尾子句
var personResult1 = from per in person
orderby per.Age ascending
group per by per.Age
into p
select p;//??有select
#endregion
6.join连接子句
#region join联接子句
//join子句可实现的3种联接关系: 1.内部联接、2.分组联接、3.左外部联接
List<Course> course = new List<Course>();
course.Add(new Course(1, "ASP.NET"));
course.Add(new Course(2, "C++"));
course.Add(new Course(3, "Python"));
//内部联接
//与inner join查询语句相似
var courseResultJoin = from p in person
join c in course on p.ID equals c.ID
select p;
foreach (var i in courseResultJoin)
{
Console.WriteLine(i.Name.ToString());
}
Console.ReadLine();
//分组联接
//含有into子句的join子句被分组联接。分组联接产生分层数据结构,它将第一个集合中的每个元素与第二个集合中的一组相关元素进行匹配。
//在查询结果中,第一个集合中的元素都会出现在查询结果中。如果第一个集合中的元素在第二个集合中找到相关元素,则使用被找到的元素,否则使用空。
var courseResultGroup = from p in person
join c in course on p.ID equals c.ID into g
select new
{
ID = p.ID,
Name = p.Name,
Age = p.Age,
Courses = g.ToList()
};
foreach (var i in courseResultGroup)
{
Console.WriteLine(i.Name + ":" + (i.Courses.Count > 0 ? i.Courses[0].CourseName : "没有选课"));
}
Console.ReadLine();
//左外部联接
//与left join查询语句相似,需要说明的是,LINQ查询表达式若要执行左外部联接,往往与DefaultIfEmpty()方法和分组联接结合起来使用。
//通常要生成两个集合的左外部联接,可以分为两步来实现:
//1)使用分组联接执行内部联接
//2)在结果集内包含第一个(左)集合的每个元素,即使该元素在右集合中没有匹配的元素也是如此。这是通过对分组联接中的每个匹配元素序列调用
// DefaultIfEmpty()方法来实现的。
var courseResultLeft = from p in person
join c in course on p.ID equals c.ID into g
from pc in g.DefaultIfEmpty()
select new
{
ID = p.ID,
Name = p.Name,
Age = p.Age,
Courses = g.ToList()
};
foreach (var i in courseResultLeft)
{
Console.WriteLine(i.Name + ":" + (i.Courses.Count > 0 ? i.Courses[0].CourseName : "没有选课"));
}
Console.ReadLine();
#endregion
7.let临时表达子句
#region let临时表达子句
//let临时表达子句,在查询表达式中,存储子表达式的结果有时很有用,这样可以在随后的子句中使用。
//可以将let关键字看作是在表达式中创建了一个临时变量用于保存表达式的结果,但是let子句指定的范围变量的只能通过初始化操作进行赋值,
//一旦初始化之后就无法再次进行更改操作。
String[] arrStr = { "Thank you so much.", "We don't talk anymore.", "I got it.", "I will surpass you." };
var arrStrResult = from arr in arrStr
let words = arr.Split(' ')
from word in words
let w = word.ToLower()
where w[0] == 'y'
select word;
//在上面代码中,使查询只能对范围变量word调用一次ToLower。如果不适用let,则必须在每个where子句的每个谓词中调用ToLower。
//let相当于一个中转变量,用于临时存储表达式的值。
foreach (var i in arrStrResult)
{
Console.WriteLine(i);
}
Console.ReadLine();
#endregion
三、LINQ查询操作
1.筛选操作Where
#region 筛选操作
//筛选操作Where
//通过Where方法和Lambda表达式处理由逻辑运算符组成的逻辑表达式
var whereResult = num.Where(i => i > 5 && i < 10 && i != 7);
foreach (var item in whereResult)
{
Console.WriteLine(item.ToString());
}
Console.ReadLine();
//上述Where方法与Lambda表达式查询的结果由LINQ查询子句也可以实现,代码如下:
var linqResult = from n in num
where n > 5 && n < 10 && n != 7
select n;
#endregion
2.投影操作Select、SelectMany
#region 投影操作
//投影操作包括以下两种:
//1)Select操作:将数据源中的元素投影到新序列中,并指定元素的类型和表现形式。
//2)SelectMany操作:将数据源中的元素投影到新序列中,并指定元素的类型和表现形式。
// 但是,SelectMany操作可以将一个函数应用到多个序列之上,并将结果合并到一个序列。
//1.Select操作
var selectResult = num.Select(data => data);
foreach (var item in selectResult)
{
Console.WriteLine(item.ToString());
}
Console.ReadLine();
//2.SelectMany操作
int[] arr1 = { 1, 2, 3 };
int[] arr2 = { 4, 5, 6 };
List<int[]> list = new List<int[]>();
list.Add(arr1);
list.Add(arr2);
var selectManyResult = list.SelectMany(data => data);
foreach (var item in selectManyResult)
{
Console.WriteLine(item.ToString());
}
Console.ReadLine();
#endregion
3.排序操作OrderBy、ThenBy..
#region 排序操作
//OrderBy方法与LINQ查询子句中的orderby子句基本类似。
//除此之外,排序操作不仅提供了OrderBy方法,还提供了其他方法进行高级排序:
//1)OrderBy操作:根据关键字对序列中的元素进行升序排序
//2)OrderByDescending操作:降序排序
//3)ThenBy操作:根据次要关键字对序列中的元素进行升序排序
//4)ThenByDescending操作:降序排序
//5)Reverse操作:将序列中的元素顺序进行反转
//OrderBy
var orderbyResult = person.OrderBy(p => p.Age).ThenBy(p => p.ID);
foreach (var item in orderbyResult)
{
Console.WriteLine("年龄:" + item.Age.ToString() + " --- 姓名:" + item.Name + " --- 编号:" + item.ID);
}
Console.ReadLine();
//Reverse
var reverseResult = person.OrderBy(p => p.Age).ThenBy(p => p.ID).Reverse();
foreach (var item in reverseResult)
{
Console.WriteLine("年龄:" + item.Age.ToString() + " --- 姓名:" + item.Name + " --- 编号:" + item.ID);
}
Console.ReadLine();
#endregion
4.聚合操作Count、Sum、Max、Min..
#region 聚合操作
//用来获取集合中的最大值、最小值、平均值、总和等一些常用的统计信息,我们称之为聚合操作,聚合常用的方法有:
//1)Count操作:数量
//2)Sum操作:和
//3)Max操作:最大
//4)Min操作:最小
//5)Average操作:平均值
//6)Aggregate操作:对集合中的元素进行自定义聚合计算
//7)LongCount操作:一般用于大型集合中的元素的数量
int[] numArr = { 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
var countResult = numArr.Count(i => i < 6);
var sumResult = numArr.Sum(i => i);
var maxResult = numArr.Max(i => i);
var minResult = numArr.Min(i => i);
var avgResult = numArr.Average(i => i);
var aggregateResult = numArr.Aggregate((x, y) => x + y);
var longcountResult = numArr.LongCount(i => i < 6);
Console.WriteLine("Count:" + countResult.ToString());
Console.WriteLine("Sum:" + sumResult.ToString());
Console.WriteLine("Max:" + maxResult.ToString());
Console.WriteLine("Min:" + minResult.ToString());
Console.WriteLine("Average:" + avgResult.ToString());
Console.WriteLine("Aggregate:" + aggregateResult.ToString());
Console.WriteLine("LongCount:" + longcountResult.ToString());
Console.ReadLine();
#endregion
5.集合操作Distinct、Except..
#region 集合操作
//在LINQ中,集合操作是指对一个序列或多个序列本身的操作,如去掉重复元素、计算两个集合的交集等操作。
//集合操作只要包括以下4种操作:
//1)Distinct操作:去掉数据源中重复元素,返回一个新序列。另外它还可以指定一个比较器来比较两个元素是否相同。
//2)Except操作:计算两个集合的差集
//3)Intersect操作:计算两个集合的交集
//4)Union操作:计算两个集合的并集
List<string> listA = new List<string>();
listA.Add("A");
listA.Add("B");
listA.Add("C");
listA.Add("D");
listA.Add("D");
List<string> listB = new List<string>();
listB.Add("C");
listB.Add("D");
listB.Add("E");
listB.Add("F");
listB.Add("G");
var listADistinct = listA.Distinct();
var listAExcept = listA.Except(listB);
var listAIntersect = listA.Intersect(listB);
var unionResult = listA.Union(listB);
WriteConsole(listA, "集合A");
WriteConsole(listB, "集合B");
WriteConsole(listADistinct.ToList<string>(), "(Distinct)去掉重复元素之后的集合A");
WriteConsole(listAExcept.ToList<string>(), "(Expect)集合A与集合B差集");
WriteConsole(listAIntersect.ToList<string>(), "(Intersect)集合A与集合B交集");
WriteConsole(unionResult.ToList<string>(), "(Union)集合A与集合B并集");
#endregion
6.元素操作ElementAt、First、Last..
#region 元素操作
//在LINQ中,元素操作可以获取计算序列中一个特定的元素。它包括以下8种操作:
/* 1)ElementAt操作:
* 2)ElementAtOrDefault操作:返回集合中指定索引处的元素,如果索引超出集合范围,则返回默认值
* 3)First操作:返回集合的第一个元素,或满足指定条件的第一个元素
* 4)FirstOrDefault操作:如果不存在满足该条件的元素,则返回默认值
* 5)Last操作:返回集合最后一个,或满足指定条件的最后一个元素
* 6)LastOrDefault操作:如果不存在满足该条件的元素,则返回默认值
* 7)Single操作:返回集合的唯一元素,或者返回集合的满足指定条件的唯一元素
* 8)SingleOrDefault操作:如果不存在满足该条件的元素,则返回默认值
*/
int elementAt = numArr.ElementAt(8);
int elementAtOrDefault = numArr.ElementAtOrDefault(21);
int first = numArr.First();
int last = numArr.Last();
//var single = numArr.Single();
Console.WriteLine("ElementAt:" + elementAt.ToString());
Console.WriteLine("ElementAtOrDefault:" + elementAtOrDefault.ToString());
Console.WriteLine("First:" + first.ToString());
Console.WriteLine("Last:" + last.ToString());
//Console.WriteLine("Single:" + single.ToString());
Console.ReadLine();
#endregion
7.数据类型转换操作AsEnumerable、AsQueryable..
#region 数据类型转换操作
/*在LINQ中,数据类型转换操作可以将数据源的类型或其元素类型转换为用户指定的类型,它包括以下8种操作:
* 1)AsEnumerable操作:可以将数据源转换成IEnumerable<T>类型的序列
* 2)AsQueryable操作:转换成IQueryable<T>或IQueryable类型的序列
* 3)Cast操作:将序列中的元素类型转换为指定的类型(由TResult参数指定)
* 4)OfType操作:从序列中筛选指定类型的元素并构建为一个序列
* 5)ToList操作:将IEnumerable<T>类型的序列转换成List<T>类型的序列
* 6)ToArray操作:将IEnumerable<T>类型的序列转换成T[]类型数组
* 7)ToDictionary操作:按照键值将序列中的元素放入一对一的字典序列(Dictionary<TKey,TValue>)中
* 8)ToLookup操作:按照键值将序列中的元素放入一对多的字典序列(Lookup<TKey,TValue>)中
*/
#endregion
8.生成操作DefaultIfEmpty、Range..
#region 生成操作
/*在LINQ中,生成操作能够产生指定的新序列,它通常包括以下4种操作:
* 1)DefaultIfEmpty操作:返回IEnumerable<T>类型的序列,如果序列为空,则返回只包含一个元素(值为默认值或指定值)的序列
* 2)Empty操作:返回IEnumerable<T>类型的空序列
* 3)Range操作:返回指定范围的数字序列
* 4)Repeat操作:返回IEnumerable<T>类型的包含一个重复值的序列
*/
int[] emptyArr = { };
var defaultValue = numArr.DefaultIfEmpty();
var emptyValue = numArr.DefaultIfEmpty(-1);
Console.WriteLine("DefaultIfEmpty():");
foreach (var i in defaultValue)
{
Console.WriteLine(i.ToString());
}
Console.ReadLine();
Console.WriteLine("DefaultIfEmpty(-1):");
foreach (var i in emptyValue)
{
Console.WriteLine(i.ToString());
}
Console.ReadLine();
#endregion
9.限定符操作All、Any、Contains
#region 限定符操作
/*在LINQ中,限定符操作可以检测序列中是否存在满足指定条件的元素,或者检测序列中的所有元素满足指定的条件,它返回一个布尔值。
* 1)All操作:检测序列中的所有元素是否都满足指定条件,如果满足则返回true,否则返回false
* 2)Any操作:检测序列中是否存在满足条件的元素
* 3)Contains操作:检测序列中是否存在指定的元素
*/
#endregion
10.连接操作Join、GroupJoin
#region 连接操作
/*LINQ只提供了两种连接操作:Join和GroupJoin。这两种连接都属于相等连接,即根据两个数据源的键是否相等来匹配这两个数据源的连接。
* 1)Join连接
* 2)GroupJoin连接
*/
var joinResult = person.Join(course,
p => p.ID,
c => c.ID,
(p, c) => new { Name = p.Name, CourseName = c.CourseName });
foreach (var i in joinResult)
{
Console.WriteLine(i.Name + ":" + i.CourseName);
}
Console.ReadLine();
var groupjoinResult = person.GroupJoin(course,
p => p.ID,
c => c.ID,
(p, c) => new { Name = p.Name, Courses = c.ToList() });
foreach (var i in groupjoinResult)
{
Console.WriteLine(i.Name + ":" + (i.Courses.Count > 0 ? i.Courses[0].CourseName : "没有选课"));
}
Console.ReadLine();
#endregion
11.SequenceEqual操作
#region SequenceEqual操作
/*SequenceEqual操作可以判断两个序列是否相等,它返回一个布尔值。即给定两个序列,入股哦这两个序列相等则必须满足以下两个条件:
* 1)序列元素数量相等,即长度相等
* 2)两个序列的对应元素相等
*/
#region SequenceEqual操作
/*SequenceEqual操作可以判断两个序列是否相等,它返回一个布尔值。即给定两个序列,入股哦这两个序列相等则必须满足以下两个条件:
* 1)序列元素数量相等,即长度相等
* 2)两个序列的对应元素相等
*/
string[] a1 = { "AB", "BC", "CD" };
string[] a2 = { "DE", "EF", "FG" };
bool result = arr1.SequenceEqual(arr2);//false
#endregion#region SequenceEqual操作
/*SequenceEqual操作可以判断两个序列是否相等,它返回一个布尔值。即给定两个序列,入股哦这两个序列相等则必须满足以下两个条件:
* 1)序列元素数量相等,即长度相等
* 2)两个序列的对应元素相等
*/
string[] a1 = { "AB", "BC", "CD" };
string[] a2 = { "DE", "EF", "FG" };
bool result = arr1.SequenceEqual(arr2);//false
#endregion
12.Concat操作
#region Concat操作
/*Concat操作可以实现序列的串联操作,将一个序列的元素全部追加到另一个序列中,并构成一个新序列。
*/
var contactResult = a1.Concat(a2);//
#endregion
13.Skip与SkipWhile操作
#region Skip与SkipWhile操作
/* Skip操作:可以生成一个新序列,他可以跳过数据源中指定数量的元素,然后返回剩余元素组成的序列
* SkipWhile操作:可以跳过数据源中满足指定条件的元素,返回剩余元素组成的序列
*/
var skipArr = num.Skip(5);//5,6,7,8,9
var skipwhileArr = num.SkipWhile((x, i) => i < 5);//5,6,7,8,9
#endregion
14.Take与TakeWhile操作
#region Take与TakeWhile操作
/* Take操作:可以生成一个序列,但和Skip操作相反。它从元素开头提取指定数量元素,然后返回由这些元素组成的序列。
* TakeWhile操作:从数据源开头提取满足指定条件的元素,然后返回由这些元素组成的序列。
*/
var takeArr = num.Take(5);//0,1,2,3,3
var takewhileArr = num.TakeWhile((x, i) => i < 5);//0,1,2,3,4
#endregion