LINQ(Language Integrated Query )语言集成查询,可为以下对象编写 LINQ 查询:SQL Server 数据库、XML 文档、ADO.NET 数据集以及支持 IEnumerable 或泛型 IEnumerable<T> 接口的任何对象集合。 此外,第三方也为许多 Web 服务和其他数据库实现提供了 LINQ 支持。
示例:
using System.Collections.Generic;
using System.Linq;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;
namespace CsharpSenior
{
class LinqHelper
{
public List<Student> Students { get; set; }
public List<Course> Courses { get; set; }
public LinqHelper()
{
GetDataSource();
}
public void Query()
{
/*一个普通查询
* 结构:from + 迭代变量名称 + in +数据源(必须是可枚举类型)
* +where(条件过滤)
* +orderby(排序,可选ascending和descending两种方式,默认的是ascending)
* +select(指定所选定的对象: 1. 整个数据项 2.数据项的一个字段 3.数据项中几个字段组成的新对象(或类似其他值))
*/
//eg:查询Age>18的对象
var query = from r in Students
where r.Age > 18
orderby r.Age
select r;
//对应的lambda表达式
var query_1 = Students.Where(r => r.Age > 18).OrderBy(r => r.Age).Select(r=>r);
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(query));
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(query_1));
//linq查询为延迟查询,只需构造一次查询语句,可以多次使用,在调用时才会执行
//eg:为集合添加一个对象,使用之前的查询
Students.Add(new Student(4,"赵五",19));
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(query));
//join 结合两个或更多集合中的数据,创建一个临时的对象集合
//eg:查询选修生物课程的学生名,通过相同的id判断
var query_2 = from r in Students
join c in Courses on r.Id equals c.Id
where c.CourseName == "生物"
select r.Name;
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(query_2));
// 利用OfType方法可以把特定类型数据筛选出来
//eg:从下列数组中获取int类型的数据
object[] objList = new object[] { 1,"张三",2,3,"李四"};
var query_3= objList.OfType<int>();
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(query_3));
//多级排序,越靠前,优先级越高
//eg:先按年龄排序,年龄一样按ID排序
var query_4 = from r in Students
orderby r.Age, r.Id
select r;
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(query_4));
//group子句可以让你把select的结果按指定的键(key)进行分组 ,每一个分组由一个叫做键的字段区分,分组本身是可枚举类型的并且可以枚举它的项
//into子句可以接受查询的一部分结构并赋予一个名字,从而可以在查询的另一部分中使用
//eg:通过课程名进行分组,选出成员数量大于2的组,形成新的集合
var query_5 = from r in Courses
group r by r.CourseName
into g
orderby g.Count() descending, g.Key
where g.Count() > 2
select new { courseName = g.Key, count = g.Count() };
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(query_5));
//通过Take()和Skip()实现只显示部分查询结果。
//通过skip跳过指定数量的元素,再通过take提取固定长度元素,可实现分页
//eg:查询Age>18,跳过第一个元素,取2个元素
Students.Add(new Student(5, "孙六", 19));
var query_6 = (from r in Students
where r.Age > 18
orderby r.Age
select r).Skip(1).Take(2);
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(query_6));
/*
* System.Linq 名称空间中的包含的类 ParallelEnumerable 可以分解查询的工作, 使其分布在多个线程上。
* 尽管 Enumerable 类给 IEnumerable<T> 接口定义了扩展方法,但 ParallelEnumerable 类的大多数扩展方法是 ParallelQuery<TSource>类的扩展。
* 一个重要的例外是 AsParallel() 方法,扩展 IEnumerable<TSource> 接口,返回 ParallelQuery<TSource>类,所以正常的集合类可以以并行方式查询。
*/
//eg
Console.WriteLine("构造大数据,耐心等待。。。");
const int count = 100000000;
var data = new int[count];
for (int i = 0; i < count; i++)
{
data[i] = new Random().Next(40);
}
Console.WriteLine("构造完成,开始查询");
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var query_7 = (from r in data
where r > 20
select r).Sum();
stopwatch.Stop();
Console.WriteLine($"正常运行耗时:{stopwatch.ElapsedMilliseconds}");
stopwatch.Restart();
var query_8 = (from r in data.AsParallel()
where r > 20
select r).Sum();
stopwatch.Stop();
Console.WriteLine($"并行运行耗时:{stopwatch.ElapsedMilliseconds}");
/*对于并行ling而言,可利用System.Threading.CancellationTokenSource设置取消长时间的查询操作。
通过.WithCancellation(Token)设置
该查询在单独的线程中运行,在该线程中,捕获一个OperationCanceledException类型的异常。如果取消了查询就触发这个异常。
在主线程中,调用CancellationTokenSource类的Cancel()方法可以取消任务
*/
//eg
var tokenSource = new CancellationTokenSource();
Task.Run(() =>
{
try
{
if (!tokenSource.IsCancellationRequested)
{
var query_9 = (from r in data.AsParallel().WithCancellation(tokenSource.Token)
where r > 5
select r).Sum();
Console.WriteLine($"查询结果:{query_9}");
}
}
catch (OperationCanceledException ex)
{
Console.WriteLine("查询取消成功");
Console.WriteLine($"异常信息:{ex.Message}");
}
});
Console.WriteLine("查询开始");
Thread.Sleep(150);
Console.WriteLine("150ms后执行取消并行查询");
tokenSource.Cancel();
// System.Collections.Concurrent.Partitioner.Create 可以手动创建分区器。
//eg
var query_10=(from r in Partitioner.Create(data,true).AsParallel()
where r > 5
select r).Sum();
Console.WriteLine($"查询结果:{query_10}");
//查找出现次数最多的元素
int[] values = new int[] { 1, 2, 5, 2, 3, 5, 5, 3, 4, 6, 3, 3 };
var query_11 = values.GroupBy(x => x).OrderByDescending(s => s.Count()).FirstOrDefault();
Console.WriteLine($"出现次数最多的元素:{query_11.FirstOrDefault()} 次数:{query_11.Count()}");
}
private void GetDataSource()
{
Students = new List<Student>
{
new Student(1,"张三",18) ,
new Student(2,"李四",19),
new Student(3,"王麻子",20)
};
Courses = new List<Course>
{
new Course(1,"语文"),
new Course(1,"数学"),
new Course(1,"英语"),
new Course(2,"语文"),
new Course(2,"历史"),
new Course(2,"生物"),
new Course(3,"语文"),
new Course(3,"化学"),
new Course(3,"生物"),
};
}
}
class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public Student(int id, string name, int age)
{
Id = id;
Name = name??null;
Age = age;
}
}
class Course
{
public int Id { get; set; }
public string CourseName { get; set; }
public Course(int id, string courseName)
{
Id = id;
CourseName = courseName ?? null;
}
}
}
调用:
LinqHelper linqHelper = new LinqHelper();
linqHelper.Query();
执行结果: