只要有集合的地方,用到运算基本就会用到Linq,简单的排序,取最大值,平均值,过滤数据,这些使用Linq非常方便,基本上实现了Sql里面常见的各种方法。在微软的EF Core中提供了使用Linq可以便捷查询数据库的数据,而不需要编写大部分数据访问代码,可通过各数据库厂商提供的程序或者第三方提供的程序访问许多不同的数据库。除了EF Core还有国人写的SqlSugar访问数据库,开源,性能也不错,功能没有EF Core多,比如数据迁移。
强调一点,EF Core的一些方法比如Add、SaveChanges,它们是微软提供的方法用来保存到数据库或其它。所以很多常说的使用Linq修改数据库,其实是EF Core或者第三方提供的方法。
下面一段是SqlSugar官方介绍:SqlSugar ORM 5.X 教程
SqlSugar是一款来自未来的ORM,拥有超前的理念,需求领跑第一线,可以毫不夸张的说,在设计理念上就算不更新几年都不会过时,我们每天都会跟踪用户需求,将这些用户需求分类和整理,把有共性的功能都整理出来,经历过长达7年的努力,需求成负增长,已经走向了成熟和完善,是一款真正用了功能齐全的ORM框架,如果你用过EF CORE或者DAPPER肯定会为功能缺失而无奈,该有的功能没有,花里胡哨的一大堆。如果你用SqlSugar, 会给你一个不错的选择, 不断给你惊喜。
Enumerable
继承IEnumerable的都可以使用Linq,它派生出来的类微软文档上好几页,只要和集合搭边,就能用。最常用的集合例如List、Array。
举一个微软的官方例子GroupBy,加了一段补充代码。
class Pet
{
public string Name { get; set; }
public double Age { get; set; }
}
public static void GroupByEx4()
{
// 创建一个Pet对象的集合.
List<Pet> petsList =
new List<Pet>{ new Pet { Name="Barley", Age=8.3 },
new Pet { Name="Boots", Age=4.9 },
new Pet { Name="Whiskers", Age=1.5 },
new Pet { Name="Daisy", Age=4.3 } };
var query = petsList.GroupBy(
pet => Math.Floor(pet.Age),//返回小于或等于Age的最大整数值,当作Key(keySelector)
pet => pet.Age,//类似sql中的要查询的列,不写的话类似select *,下面的样例就是
(baseAge, ages) => new
{
Key = baseAge,
Count = ages.Count(),
Min = ages.Min(),
Max = ages.Max()
});
//再写一个补充,加深理解,和上面结果一样
var query1 = petsList.GroupBy(
pet => Math.Floor(pet.Age),
(baseAge, ages) => new
{
Key = baseAge,
Count = ages.Count(),
Min = ages.Min(p=>p.Age),
Max = ages.Max(p => p.Age),
});
// Iterate over each anonymous type.
foreach (var item in query)
{
Console.WriteLine("\nAge group: " + item.Key);
Console.WriteLine("Number of pets in this age group: " + item.Count);
Console.WriteLine("Minimum age: " + item.Min);
Console.WriteLine("Maximum age: " + item.Max);
}
foreach (var item in query1)
{
Console.WriteLine("\nAge group: " + item.Key);
Console.WriteLine("Number of pets in this age group: " + item.Count);
Console.WriteLine("Minimum age: " + item.Min);
Console.WriteLine("Maximum age: " + item.Max);
}
/* This code produces the following output:
Age group: 8
Number of pets in this age group: 1
Minimum age: 8.3
Maximum age: 8.3
Age group: 4
Number of pets in this age group: 2
Minimum age: 4.3
Maximum age: 4.9
Age group: 1
Number of pets in this age group: 1
Minimum age: 1.5
Maximum age: 1.5
*/
}
Queryable
与Enumerable,都在程序集System.Linq中,都是对集合的扩展,只是Queryable的方法是对IQueryable的扩展,而Enumerable是对IEnumerable的扩展,方法名字看上去很类似,Why,有啥区别,看看参数发现Queryable里面多了一个Expression,Expression是基类,表示表达式树节点的类派生自该基类。
IQueryable<T>接口继承IEnumerable<T>接口,因此,AsQueryable()就可以转换成IQueryable了。
别懵,下面会稍微解释下用法的区别,不懂的话记得读取数据库这些使用Queryable的方法就行了。
代码演示下GroupBy,还用上面的数据,其实就是多了一个AsQueryable()
//Enumerable方法
var query = petsList.GroupBy(
pet => Math.Floor(pet.Age),
pet => pet.Age,
(baseAge, ages) => new
{
Key = baseAge,
Count = ages.Count(),
Min = ages.Min(),
Max = ages.Max(),
});
//Queryable方法,表达式数
var query1 =petsList.AsQueryable().GroupBy(
pet => Math.Floor(pet.Age),
pet => pet.Age,
(baseAge, ages) => new
{
Key = baseAge,
Count = ages.Count(),
Min = ages.Min(),
Max = ages.Max(),
});
Expression<Func<T, bool>>与Func<T, bool>
Func<T, bool>就是一个委托,不明白的话可以看看前面的文章,主要是(二、三)。
Linq如何使用(一)委托Delegate - 简书 (jianshu.com)
Linq如何使用(二)Lambda 声明委托Delegate
Linq如何使用(三)使用Linq-自己写一个实现方法
先看下下面代码
Func<int, bool> fun1 = num => num < 5;
Expression<Func<int, bool>> exfun1 = num => num < 5;
Console.WriteLine(fun1(4));//true
Console.WriteLine(exfun1.Compile()(4));//true
exfun1调用了一个Compile()方法就是委托了。Expression<Func<T, bool>>是一个表达式树,是不能直接调用,我们再用代码分析下Expression。
Expression<Func<int, bool>> exfun1 = num => num < 5;
var param = exfun1.Parameters[0];
BinaryExpression operation = (BinaryExpression)exfun1.Body;
Console.WriteLine($"参数:{param},方法:{operation}");
//输出 参数:num,方法:(num < 5)
Console.WriteLine($"{operation.Left} {operation.NodeType} {operation.Right}");
//输出 num LessThan 5
//LessThan就是小于
想深入研究的可以自行查资料,也可以反编译看看生成的东西,简而言之,访问数据库的时候where查询一定要用表达式树,微软会帮我们把条件转换成sql里面的Where,要是使用Enumerable里面的方法就是全表查询出结果再过滤条件了,网上应该很多例子,也可以自己跟踪数据库访问。
ps:某些情况,比如计算大量KPI,需要使用Where,SUM,MAX,表关联等等其它运算操作,仅使用Queryable在数据库层面计算相关结果,会影响数据库性能,可能就会需要Queryable和Enumerable的关联了,应用服务器使用Queryable读取到数据库相关数据,再使用Enumerable内存运算,就可以一定程度上避免数据库的性能瓶颈。