Linq是什么
- LINQ是Language Integrate Query的缩写,意为语言集成查询,是微软在.Net Framework 4.5版中推出的主要特性之一。
- 它为开发人员提供了统一的数据查询模式,并与.Net开发语言(如C#和VB.Net)集成,很大程度上简化了数据查询的编码和调试工作,提供了数据查询的性能。
- LINQ中查询表达式访问的是一个对象,而该对象可以表示为各种类型的数据源。比如SQL Server数据库,XML文档,ADO.NET数据集,以及内存中的数据集合等。
- 在.NET类库中,LINQ相关类库都在Systenq命名空间中,该命名空间提供支持使用LINQ进行查询的类和接口,其中主要是以下两个接口和两个类:
- IEnumerable< T >接口:它表示可以查询的数据集合,一个查询通常是逐个对集合对象中的元素进行筛选操作,返回一个新的IEnumerable< T >对象,用来保存查询结果。
- IQueryable< T >接口:它继承自IEnumerable< T >接口,表示一个可以查询的表达式目录树。
- Enumerable类:它通过对IEnumerable< T >提供扩展方法,实现LINQ标准查询运算。包括过滤、导航、排序、关联、求和、求最大值、求最小值等操作。
- Queryable类:它通过对IQueryable< T >提供扩展方法,实现LINQ标准查询运算。包括过滤、导航、排序、关联、求和、求最大值、求最小值等操作。
- Linq提供以下数据源的查询功能:
- 支持 IEnumerable 或泛型 IEnumerable 接口的任何对象集合
- SQL Server 数据库
- XML文档
- ADO.NET数据库
- Web 服务和其他数据库
传统查询与Linq查询
使用Linq需要先引入命名空间System.Linq;
eg:查询等级>=2的雇员
class Employee
{
public int Id { get;private set; }
public string Name { get;private set; }
public int Age { get;private set; }
public int LevelNum { get;private set; }
public Employee(int id,string name,int age,int levelNum)
{
this.Id = id;
this.Name = name;
this.Age = age;
this.LevelNum = levelNum;
}
public override string ToString()
{
return string.Format("ID={0},Name={1},Age={2},LevelNum={3}", this.Id, this.Name, this.Age, this.LevelNum);
}
}
class EmpLevel
{
public int Id { get; private set; }
public int LevelNum { get; private set; }
public string LevelName { get; private set; }
public float Salary { get; private set; }
public EmpLevel(int id,int levelNum,string levelName,float salary)
{
this.Id = id;
this.LevelName = levelName;
this.LevelNum = levelNum;
this.Salary = salary;
}
public override string ToString()
{
return string.Format("ID={0},LevelNum={1},LevelName={2},Salary={3}", this.Id, this.LevelNum, this.LevelName, this.Salary);
}
}
class Test
{
List<EmpLevel> empLeArray;
List<Employee> empArray;
List<Employee> empQueryResult;
//构造函数
public Test()
{
empArray = new List<Employee>();
empLeArray = new List<EmpLevel>();
empQueryResult = new List<Employee>();
empArray.Add(new Employee(1, "张三", 30, 2));
empArray.Add(new Employee(4, "王一", 36, 2));
empArray.Add(new Employee(2, "李四", 20, 1));
empArray.Add(new Employee(3, "王五", 35, 3));
empLeArray.Add(new EmpLevel(1, 1, "1级", 5000));
empLeArray.Add(new EmpLevel(2, 2, "2级", 8000));
empLeArray.Add(new EmpLevel(3, 3, "3级", 10000));
}
//普通写法
public void Test1()
{
foreach (Employee emp in empArray)
{
if (emp.LevelNum >= 2)
{
empQueryResult.Add(emp);
}
}
foreach (Employee emp in empQueryResult)
{
Console.WriteLine(emp.ToString());
}
}
//Linq写法
//var关键字是一种定义变量的数据类型
//var可以代替数据类型,在编译时根据上下文来判断你想使用什么样的类型
public void Test2()
{
var resule = from m in empArray
where m.LevelNum >= 2
select m;
foreach (var item in resule)
{
Console.WriteLine(item);
}
}
}
Linq扩展方法查询
扩展方法是什么
- 扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。
- 扩展方法是一种特殊的静态方法,调用扩展方法与调用在类型中实际定义的方法之间没有明显的差异
扩展方法如何编写
- 扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。
- 只有静态类才能增加扩展方法
- 它们的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。
- 扩展方法必须要有三个参数分别是this,要扩展的类型、对象名称,比如public static string Test(this string name)。
- 只有使用 using 指令将命名空间显式导入到源代码中之后,扩展方法才能位于范围中。
- 调用扩展方法必须要使用对象来调用
static class Test2
{
public static void Test1()
{
string str = "Hello";
string strR = str.Test();
Console.WriteLine(strR);
}
//这里Test就是一个拓展方法
public static string Test(this string name)
{
return name + "World";
}
}
Linq扩展方法
eg:查询等级>=2的雇员
//linq扩展方法查询
public void Test3()
{
var result = empArray.Where(FilterCondition);//使用where扩展方法过滤出符合的项目
foreach (var item in result)
{
Console.WriteLine(item);
}
}
//拓展方法过滤条件
private bool FilterCondition(Employee employee)
{
if (employee.LevelNum >= 2)
{
return true;
}
else
{
return false;
}
}
//扩展方法使用lambda表达式
public void Test4()
{
var result = empArray.Where(e => e.LevelNum >= 2);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
Linq联合查询(并集)
普通方法
eg:查询雇员与雇员级别的并集
//联合查询查询出两个集合的并集(雇员与雇员级别)
public void Test5()
{
var result = from e in empArray
from l in empLeArray
select new { e, l };
foreach (var item in result)
{
Console.WriteLine(item.ToString());
}
}
eg:输出所有级别大于等于2的雇员姓名、级别名称、工资
public void Test6()
{
var result = from e in empArray
from l in empLeArray
where e.LevelNum == l.LevelNum && e.LevelNum >= 2
select new { e.Name, l.LevelName, l.Salary };
foreach (var item in result)
{
Console.WriteLine(item.ToString());
}
}
Join On方法
eg:输出所有级别大于等于2的雇员姓名、级别名称、工资
public void Test8()
{
var result = from e in empArray
join l in empLeArray
on e.LevelNum equals l.LevelNum
where e.LevelNum == l.LevelNum && e.LevelNum >= 2
select new { e.Name, l.LevelName, l.Salary };
foreach (var item in result)
{
Console.WriteLine(item.ToString());
Linq查询结果排序
eg:输出所有级别大于等于2的雇员id、姓名、级别名称、工资,按照编号和级别降序排序
public void Test7()
{
var result = from e in empArray
from l in empLeArray
where e.LevelNum == l.LevelNum && e.LevelNum >= 2
orderby e.Id descending, e.LevelNum descending
select new { e.Id, e.Name, l.LevelName, l.Salary };
foreach (var item in result)
{
Console.WriteLine(item.ToString());
}
}
- 排序关键字:orderby
- 降序关键字:descending
- 写在前面的排序条件优先级更高
group by into进行分组查询
eg:对雇员信息集合,按照级别进行分组查询,查询统计每个级别的人员数量
public void Test9()
{
var result = from e in empArray
group e by e.LevelNum into g
select new { g.Key, counts = g.Count() };
foreach (var item in result)
{
Console.WriteLine("级别:" + item.Key + " 个数:" + item.counts);
}
}
any all关键字
- any表示是否至少有一个满足查询条件
- all表示必须都满足查询条件
eg:集合中是否有/都是以张三为姓名的项目
public void Test10()
{
bool result = empArray.Any(m => m.Name == "张三");
Console.WriteLine("集合中是否有以张三为姓名的项目:" + result);
}
public void Test11()
{
bool result = empArray.All(m => m.Name == "张三");
Console.WriteLine("集合中是否都是以张三为姓名的项目:" + result);
附录:输出结果
static void Main(string[] args)
{
Test test = new Test();
test.Test1();
Console.WriteLine("---------------------");
test.Test2();
Console.WriteLine("---------------------");
Test2.Test1();
Console.WriteLine("---------------------");
test.Test3();
Console.WriteLine("---------------------");
test.Test4();
Console.WriteLine("---------------------");
test.Test5();
Console.WriteLine("---------------------");
test.Test6();
Console.WriteLine("---------------------");
test.Test7();
Console.WriteLine("---------------------");
test.Test8();
Console.WriteLine("---------------------");
test.Test9();
Console.WriteLine("---------------------");
test.Test10();
Console.WriteLine("---------------------");
test.Test11();
Console.ReadKey();
}
/*输出:
ID=1,Name=张三,Age=30,LevelNum=2
ID=4,Name=王一,Age=36,LevelNum=2
ID=3,Name=王五,Age=35,LevelNum=3
---------------------
ID=1,Name=张三,Age=30,LevelNum=2
ID=4,Name=王一,Age=36,LevelNum=2
ID=3,Name=王五,Age=35,LevelNum=3
---------------------
HelloWorld
---------------------
ID=1,Name=张三,Age=30,LevelNum=2
ID=4,Name=王一,Age=36,LevelNum=2
ID=3,Name=王五,Age=35,LevelNum=3
---------------------
ID=1,Name=张三,Age=30,LevelNum=2
ID=4,Name=王一,Age=36,LevelNum=2
ID=3,Name=王五,Age=35,LevelNum=3
---------------------
{ e = ID=1,Name=张三,Age=30,LevelNum=2, l = ID=1,LevelNum=1,LevelName=1级,Salary=5000 }
{ e = ID=1,Name=张三,Age=30,LevelNum=2, l = ID=2,LevelNum=2,LevelName=2级,Salary=8000 }
{ e = ID=1,Name=张三,Age=30,LevelNum=2, l = ID=3,LevelNum=3,LevelName=3级,Salary=10000 }
{ e = ID=4,Name=王一,Age=36,LevelNum=2, l = ID=1,LevelNum=1,LevelName=1级,Salary=5000 }
{ e = ID=4,Name=王一,Age=36,LevelNum=2, l = ID=2,LevelNum=2,LevelName=2级,Salary=8000 }
{ e = ID=4,Name=王一,Age=36,LevelNum=2, l = ID=3,LevelNum=3,LevelName=3级,Salary=10000 }
{ e = ID=2,Name=李四,Age=20,LevelNum=1, l = ID=1,LevelNum=1,LevelName=1级,Salary=5000 }
{ e = ID=2,Name=李四,Age=20,LevelNum=1, l = ID=2,LevelNum=2,LevelName=2级,Salary=8000 }
{ e = ID=2,Name=李四,Age=20,LevelNum=1, l = ID=3,LevelNum=3,LevelName=3级,Salary=10000 }
{ e = ID=3,Name=王五,Age=35,LevelNum=3, l = ID=1,LevelNum=1,LevelName=1级,Salary=5000 }
{ e = ID=3,Name=王五,Age=35,LevelNum=3, l = ID=2,LevelNum=2,LevelName=2级,Salary=8000 }
{ e = ID=3,Name=王五,Age=35,LevelNum=3, l = ID=3,LevelNum=3,LevelName=3级,Salary=10000 }
---------------------
{ Name = 张三, LevelName = 2级, Salary = 8000 }
{ Name = 王一, LevelName = 2级, Salary = 8000 }
{ Name = 王五, LevelName = 3级, Salary = 10000 }
---------------------
{ Id = 4, Name = 王一, LevelName = 2级, Salary = 8000 }
{ Id = 3, Name = 王五, LevelName = 3级, Salary = 10000 }
{ Id = 1, Name = 张三, LevelName = 2级, Salary = 8000 }
---------------------
{ Name = 张三, LevelName = 2级, Salary = 8000 }
{ Name = 王一, LevelName = 2级, Salary = 8000 }
{ Name = 王五, LevelName = 3级, Salary = 10000 }
---------------------
级别:2 个数:2
级别:1 个数:1
级别:3 个数:1
---------------------
集合中是否有以张三为姓名的项目:True
---------------------
集合中是否都是以张三为姓名的项目:False
*/
附录:参考资料
https://baike.baidu.com/item/LINQ/4462670?fr=aladdin
https://www.bilibili.com/video/BV1G7411c773
https://www.cnblogs.com/marshhu/p/6939763.html
https://www.cnblogs.com/sf-2020/p/14190468.html
https://blog.csdn.net/han_yankun2009/article/details/25334021