.NET教程 - LINQ
更新记录
转载请注明出处:
2022年9月30日 发布。
2022年9月29日 从笔记迁移到博客。
LINQ基础(LINQ Fundamentals)
LINQ介绍说明#
LINQ(发音Link)语言集成查询(Language Intergrated Query)
LINQ是.NET框架的扩展,允许我们以使用SQL类似的语法查询数据集合,可以嵌入到.NET支持的语言中,比如:C#和VB。但要注意LINQ和SQL很类似,但是两者是完全不同的东西。查询的数据源可以是Array、List、XML、JSON、数据库等。通过使用IEnumerable<T>
和IQueryable<T>
实现对数据源的查询和操作。LINQ还支持可以从远程数据源(如sqlserver数据库)动态提供的序列。standard query operators are implemented as extension methods
注意:
- A query operator never alters the input sequence; instead, it returns a new sequence。
- Each method on IEnumerable
<T>
is a standard query operator,it provides querying capability over the collection on which it operates。 - LINQ定义在using System.Linq;命名空间下。
- LINQ中的Enumerable接口的扩展方法定义在System.Linq命名空间中。
- 该命名空间中定义了超过了40个查询运算符。
- 所有的定义都是静态扩展方法(static extension methods)。
- 使用LINQ项目必须基于.NET Framework 3.5以上。
LINQ的作用(为什么要使用LINQ)#
- 更加高效、快速、简单的查询、操作数据。
- 提高代码的可读性、可维护性。
- 在程序中可以直接使用类似SQL的数据查询语法,类似SQL上手简单。
- 提高开发效率
LINQ的优势#
1、熟悉的语言:开发人员不必为每种类型的数据源或数据格式学习新的语言。
2、更少的编码:相比较传统的方式,LINQ减少了要编写的代码量。
3、可读性强:LINQ增加代码可读性,因此其他开发人员可以很轻松地理解和维护。
4、标准化的查询方式:可以使用相同的LINQ语法查询多个数据源。
5、类型检查:程序会在编译的时候提供类型检查。
6、智能感知提示:LINQ为通用集合提供智能感知提示。
7、整形数据:LINQ可以检索不同形状的数据。
LINQ组成#
LINQ由不同的部分组成,分别是 必须的部分 和 可选的部分
扩展方法(Extension methods)
这是必须的部分
比如Where、OrderBy、Select
LINQ数据提供工具(LINQ providers)
这是必须的部分
用于处理不同的数据源
比如LINQ to Objects, LINQ to Entities, LINQ to XML, LINQ to OData、LINQ to Amazon
Lambda表达式(Lambda expressions)
这是可选的部分
用于代替类似SQL语法的查询语法
LINQ查询语法(LINQ query comprehension syntax)
这是可选的部分
类似SQL的查询语法
比如from, in, where, orderby, descending, and select
主要命名空间#
using System.Linq // LINQ to Objects and PLINQ
using System.Linq.Expressions // For building expressions manually
using System.Xml.Linq // LINQ to XML
LINQ数据提供程序#
LINQ支持不同的数据源
比如:SQL数据库、对象、XML等,需要由不同的提供程序进行支持
LINQ to XML 使用LINQ操作和查询XML文档
LINQ to SQL 针对SQL的查询
LINQ to Dataset 针对ADO.NET DataSet对象使用的LINQ
LINQ to Entity 针对ADO.NET Entity Framework(EF)的LINQ
LINQ to Objects 针对数组和集合的LINQ查询
Parallel LINQ 并行处理LINQ查询返回的数据
LINQ还可以自己进行扩展,比如:LINQ to Amazon
LINQ to SQL组件,可以查询基于关系数据库的数据,并对这些数据进行检索、插入、修改、删除、排序、聚合、分区等操作
LINQ to DataSet组件,可以查询DataSet对象中的数据,并对这些数据进行检索、过滤、排序等操作
LINQ to Objects组件,可以查询Ienumerable或Ienumerable集合,也就是可以查询任何可枚举的集合,如数据(Array和ArrayList)、泛型列表List、泛型字典Dictionary等,以及用户自定义的集合,而不需要使用LINQ提供程序或API
LINQ to XML组件,可以查询或操作XML结构的数据(如XML文档、XML片 段、XML格式的字符串等),并提供了修改文档对象模型的内存文档和支持LINQ 查询表达式等功能,以及处理XML文档的全新的编程接口
LINQ相关的泛型接口#
LINQ注意问题#
LINQ是强类型
如果需要立即获得值,使用转换API
最好定义在方法内
LINQ不是强制使用的,在一定条件下可以不使用
LINQ规范#
使用隐式var进行声明
因为一般返回类型是一个IEnumerable
匿名对象#
即不需要类即可直接生成一个对象,类似Javascript中对象直接量
语法#
使用#
注意#
匿名类型只能用在局部变量中,不能作为类成员
由于匿名类型没有名字,所以只能使用var作为变量的类型
不能设置匿名类型对象的属性,编译去为匿名类型创建的属性是只读的
LINQ语句延迟执行(Deferred Execution)(Lazy Evaluation)#
LINQ语句会延迟执行
而不是在创建的时候就执行,而是在访问的时候才执行
以下情况不会延迟执行:
1、运算返回单个值或标量值(single element or scalar)
比如:element、aggregation、quantifiers operators
2、存在转换操作符
比如:ToArray、ToList、ToDictionary、ToLookup、ToHashSet
LINQ操作的三种分类
Sequence in, sequence out (sequence→sequence)
Sequence in, single element or scalar value out
Nothing in, sequence out (generation methods)
Sequence→Sequence#
说明#
大部分的LINQ操作都是属于这种类型
示意图
主要包含LINQ操作#
FILTERING(过滤)#
IEnumerable
Returns a subset of the original elements
With each of the filtering methods, you always end up with either the same number or fewer elements than you started with
主要操作方法:
Where Returns a subset of elements that satisfy a given condition
Take Returns the first count elements and discards the rest
Skip Ignores the first count elements and returns the rest
TakeWhile Emits elements from the input sequence until the predicate is false
SkipWhile Ignores elements from the input sequence until the predicate is false
and then emits the rest
Distinct Returns a sequence that excludes duplicates
PROJECTING(投影)#
IEnumerable
Transforms each element with a lambda function
主要操作方法:
Select, SelectMany
JOINING(连接)#
IEnumerable
Meshes elements of one sequence with another
主要操作方法:
Join, GroupJoin, Zip
ORDERING(排序)#
IEnumerable
Returns a reordering of a sequence
主要操作方法:
OrderBy, OrderByDescending, ThenBy, ThenByDescending, Reverse
GROUPING(分组)#
IEnumerable
Groups a sequence into subsequences
主要操作方法:
GroupBy
SET OPERATORS(集合操作符)#
IEnumerable
Takes two same-typed sequences and returns their commonality, sum, or difference
主要操作方法:
Concat, Union, Intersect, Except
CONVERSION METHODS: IMPORT(转换方法:导入)#
IEnumerable→IEnumerable
主要操作方法:
OfType, Cast
CONVERSION METHODS: EXPORT(转换方法:导出)#
IEnumerable
主要操作方法:
ToArray, ToList, ToDictionary, ToLookup, AsEnumerable, AsQueryable
Sequence→Element or Value#
说明#
主要包含LINQ操作#
ELEMENT OPERATORS(元素操作)#
IEnumerable
Picks a single element from a sequence
主要操作方法:
First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault,
ElementAt, ElementAtOrDefault, DefaultIfEmpty
AGGREGATION METHODS(聚合操作)#
IEnumerable
Performs a computation across a sequence, returning a scalar value (typically a number)
主要操作方法:
Aggregate, Average, Count, LongCount, Sum, Max, Min
QUANTIFIERS(逻辑比较)#
IEnumerable
An aggregation returning true or false
主要操作方法:
All, Any, Contains, SequenceEqual
Void→Sequence#
说明#
主要包含LINQ操作#
GENERATION METHODS(生成方法)#
void→IEnumerable
Manufactures a simple sequence
主要操作方法:
Empty, Range, Repeat
方法语法(extension methods) 和 查询语法(Query Expressions)
概述#
LINQ支持两种形式的语法:
查询表达式语法(Query Expressions) 和 方法语法(extension methods)
查询表达式语法(Query Expressions):和SQL类似,使用查询表达式形式书写
方法语法(extension methods):使用标准的方法调用,使用Fluent Syntax风格
注意:接受值并返回bool的lambda表达式称为谓词(predicate)
查询表达式(Query expressions) 和 方法调用(fluent queries)对比#
查询表达式支持的操作少于方法调用,有时候需要转为方法调用形式或混合方法调用
查询表达式可以使用let子句
方法链式(extension methods)调用示意图#
查询表达式(Query Expressions)结构示意图#
混合式查询(Mixed-Syntax Queries)#
可以混合 LINQ方法形式 和 LINQ表达式形式 的语法进行查询
实例:混合筛选
int[] tests = new int[] { 1, 2, 3, 4, 5 };
int result = (from item in tests where item > 3 select item).Count();
Console.WriteLine(result); //2
查询表达式语法(Query Expressions)
说明#
查询语法是声明式的,方法语法是命令式的
查询语法 和 方法语法 没有性能差异,编译器会将查询语法转为方法调用形式
查询表达式总是以from子句开头,以select或group子句结尾
编译器最终会将查询表达式转为方法调用的形式来处理LINQ
实例:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Panda
{
class Panda
{
static void Main(string[] args)
{
int[] numbers = { 1, 2, 3, 4, 5, 6, 7 }; //对象集合
//查询语法
IEnumerable<int> minNumber1 = from i in numbers
where i <= 3
select i;
foreach (int item in minNumber1)
{
Console.WriteLine(item);
}
//查询语法
IEnumerable<int> minNumber2 = numbers.Where(x => x <= 3);
foreach (int item in minNumber2)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
还可以把查询语法和方法语法结合使用
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[]
{
1,2,3,4,5,6,7
};
//结合使用
int queryResult = (from n in numbers
where n < 3
select n).Count();
Console.WriteLine(queryResult);
//wait
Console.ReadKey();
}
}
}
查询表达式语法结构(Query expression syntax)图#
LINQ查询语法与SQL语法对比(Query Syntax Versus SQL Syntax)#
LINQ查询语法遵循C#表达式
LINQ操作按元素顺序处理,是有序的
LINQ方法形式 与 查询表达式形式对比(Query Syntax Versus Fluent Syntax)#
查询表达式在以下方面更加方便:
使用let子句进行引入新的临时变量
使用SelectMany, Join, or GroupJoin子句
单个子句的情况下,方法形式更加方便
查询变量#
LINQ查询的返回值为可枚举类型(不是枚举类型) 或 标量(scalar)
说明:
如果查询表达式返回可枚举类型,查询会一直等到出来可枚举变量时才执行
如果可枚举变量被处理多次,查询就会执行多次
如果可枚举变量在遍历之后,查询之前的数据有改动,查询会使用新数据
如果查询表达式返回标量,查询立即执行,并且把结果保存在查询变量中
避免LINQ多次执行#
To avoid such repeated execution, you must cache the data that the executed query retrieves
To do so, you assign the data to a local collection using one of the To collection methods
During the assignment call of a To method, the query obviously executes
However, iterating over the assigned collection after that point will not involve the query expression any further
In general, if you want the behavior of an in-memory collection snapshot,
it is a best practice to assign a query expression to a cached collection to avoid unnecessary iterations
范围变量(Range Variables)#
The identifier immediately following the from keyword syntax is called the range variable
实例:
from n in names // n is our range variable
where n.Contains ("a") // n = directly from the array
orderby n.Length // n = subsequent to being filtered
select n.ToUpper() // n = subsequent to being sorted
可以通过以下方式引入range variables:
let
into
An additional from clause
join
let关键字#
在查询表达式中可以使用let关键字引入一个临时的变量
实例:
string[] names = { "Tom","Dick","Harry","Mary","Jay" };
IEnumerable<string> query =
from n in names
let vowelless = Regex.Replace (n, "[aeiou]", "")
where vowelless.Length > 2
orderby vowelless
select n + " - " + vowelless;
查询延续(Query Continuations)#
使用into关键字延续查询
注意:into子句必须要放在select和group后面
实例:
from c in "The quick brown tiger".Split()
select c.ToUpper() into upper
where upper.StartsWith ("T")
select upper
延迟执行(Deferred Execution)
说明#
LINQ语句一般都会在使用的时候才会执行,除以下情况:
Operators that return a single element or scalar value, such as First or Count
包含转换操作ToArray, ToList, ToDictionary, ToLookup, ToHashSet
重新评估(Reevaluation)#
在执行时会再次检测序列,以最新的序列进行执行LINQ操作
重新评估的缺点#
有时候想锁住或缓存序列的当前值
密集查询/远程查询没有缓存,重复计算会导致效率低下
实例:重新评估
var numbers = new List<int>() { 1, 2 };
IEnumerable<int> query = numbers.Select (n => n * 10);
foreach (int n in query) Console.Write (n + "|"); // 10|20|
numbers.Clear();
foreach (int n in query) Console.Write (n + "|"); // <nothing>
防止重复评估的方法#
将序列的LINQ查询结果转为其他集合,比如使用ToArray or ToList操作
实例:防止重复评估执行
var numbers = new List<int>() { 1, 2 };
List<int> timesTen = numbers
.Select (n => n * 10)
.ToList(); // Executes immediately into a List<int>
numbers.Clear();
Console.WriteLine (timesTen.Count); // Still 2
捕获变量(Captured Variables)#
如果LINQ查询中的lambda表达式捕获外部变量
则在运行LINQ查询时再去获得变量的值
实例:运行LINQ时捕获变量值
int[] numbers = { 1, 2 };
int factor = 10;
IEnumerable<int> query = numbers.Select (n => n * factor);
factor = 20;
foreach (int n in query) Console.Write (n + "|"); // 20|40|
实例:运行LINQ时捕获变量值
IEnumerable<char> query = "Not what you might expect";
string vowels = "aeiou";
for (int i = 0; i < vowels.Length; i++)
{
query = query.Where (c => c != vowels[i]);
}
//这里会报错
//因为循环已经退出,所以i超出了索引范围、
//抛出IndexOutOfRangeException 异常
foreach (char c in query) Console.Write (c);
//修复方式
// for (int i = 0; i < vowels.Length; i++)
// {
// char vowel = vowels[i];
// query = query.Where (c => c != vowel);
// }
延迟执行的内部原理(How Deferred Execution Works)#
本质是装饰器(decorator)和代理(Proxy)设计模式
使用用户定义的条件来修饰序列
示意图
如果是多个LINQ操作,则会进行多层的装饰(Chaining Decorators)
注意:如果调用转换操作,比如ToList则会马上进行执行所有操作
LINQ查询如何执行(How Queries Are Executed)#
执行LINQ查询会层层进行操作的调用,然后再返回数据
自定义LINQ操作
说明#
只需要定义IEnumerable
实例:
public static IEnumerable<TResult> MySelect<TSource,TResult>(this IEnumerable<TSource> source, Func<TSource,TResult> selector)
{
foreach (TSource element in source)
yield return selector (element);
}
LINQ子查询(Subqueries)#
A subquery is a query contained within another query’s lambda expression
类似SQL中的子查询
每当计算封闭lambda表达式时,都会执行子查询
这意味着子查询是根据外部查询的需要执行的
子查询示意图:
实例:包含子查询的LINQ查询
string[] musos = { "Item1", "Item2", "Item3", "Item5" };
IEnumerable<string> query = musos.OrderBy(m => m.Split().Last());
实例:跨Lambda表达式的变量#
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IEnumerable<string> outerQuery = names
.Where (n => n.Length == names.OrderBy (n2 => n2.Length)
.Select (n2 => n2.Length).First());
// Tom, Jay
实例:子查询#
IEnumerable<string> outerQuery =
from n in names
where n.Length ==
(from n2 in names orderby n2.Length select n2.Length).First()
select n;
LINQ操作组合策略(Composition Strategies)
渐进式查询构造(Progressive query construction)
将多个操作放置到多条语句中
使用into关键词(Using the into keyword)
将查询的结果放置到一个变量中,再进行其他查询
包裹查询(Wrapping queries)
类型与子查询
实例:渐进式查询构造
var filtered = names .Where (n => n.Contains ("a"));
var sorted = filtered .OrderBy (n => n);
var query = sorted .Select (n => n.ToUpper());
实例:into关键字
IEnumerable<string> query =
from n in names
select n.Replace ("a", "").Replace ("e", "").Replace ("i", "")
.Replace ("o", "").Replace ("u", "")
into noVowel
where noVowel.Length > 2 orderby noVowel select noVowel;
实例:包裹查询
IEnumerable<string> query =
from n1 in
(
from n2 in names
select n2.Replace ("a", "").Replace ("e", "").Replace ("i", "")
.Replace ("o", "").Replace ("u", "")
)
where n1.Length > 2 orderby n1 select n1;
投影策略(Projection Strategies)
说明#
最终生成的序列的类型
投影是什么#
把集合中的每一项转换为另外一种类型。
IEnumerable<int> ages = list.Select(e =>e.Age);
IEnumerable<string> names = list.Select(e=>e.Gender?"男":"女");
var dogs = list.Select(p=>new Dog{NickName=e.Name,Age=e.Age});
主要有三种方式自定义生成的类型:
实例化指定类型(Object Initializers)
匿名类型(Anonymous Types)
使用let关键字(The let Keyword)
实例化指定类型(Object Initializers)#
实例:实例化指定类型
select new TempClassItem
{
Property1 = item.Property,
Property2 = item.Property2
};
匿名类型(Anonymous Types)#
实例:匿名类型
var intermediate = from n in names
select new
{
Property1 = item.Property1,
Property2 = item.Property2
};
实例:实例let关键字#
IEnumerable<string> query =
from n in names
let vowelless = n.item
where vowelless.Length > 2
orderby vowelless
select n; // Thanks to let, n is still in scope
解释查询(Interpreted Queries)
说明#
LINQ provides two parallel architectures
local queries for local object collections
interpreted queries for remote data sources
本地查询(local queries)使用IEnumerable
远程查询(remote queries)使用IQueryable
IQueryable
IQueryable
DbSet
将本地查询的IEnumerable
将本地查询的IQueryable
EF Core中的查询大都是IQueryable
实例:EF Core查询
IQueryable<string> query = from c in dbContext.Customers;
解释查询的工作原理(How Interpreted Queries Works)#
First, the compiler converts query syntax to fluent syntax
Next, the compiler resolves the query operator methods
EF Core加载导航属性的值(LOADING NAVIGATION PROPERTIES)
默认情况下EF Core不会自动加载导航属性
方法一:使用Include()方法
var cust = dbContext.Customers
.Include (c => c.Purchases)
.Where (c => c.ID == 2).First();
方法二:使用投影
var custInfo = dbContext.Customers
.Where (c => c.ID == 2)
.Select (c => new
{
Name = c.Name,
Purchases = c.Purchases.Select (p => new { p.Description, p.Price })
})
.First();
方法三:显式加载(explicit loading)
dbContext.Entry (cust).Collection (b => b.Purchases).Load();
延迟加载(LAZY LOADING)
设置全局延迟加载#
dbContext.Entry (cust).Collection (b => b.Purchases).Load();
//引入命名空间
using Microsoft.EntityFrameworkCore.Proxies;
//在DbContext中设置
protected override void OnConfiguring (DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies();
//...
}
查询表达式结构语法
说明#
子句必须按照一定的顺序出现
from和select子句是必须的,其他子句可选
与SQL不同,LINQ的select子句在表达式最后
可以有任意多个from….let…..where子句
每个子句概要:
查询语法汇总
Method | Description |
---|---|
First, FirstOrDefault | 获得第一个元素或者其类型的默认值 比如int默认为0,引用类型默认为null |
Last, LastOrDefault | 获得最后一个元素或者其类型的默认值 比如int默认为0,引用类型默认为null |
Where | 条件筛选 |
Single, SingleOrDefault | 获得满足条件的单个元素或其默认值 |
ElementAt, ElementAtOrDefault | 获得一个指定索引上的值或返回默认值 |
Select, SelectMany | 选择元素的一部分或组成其他类型 |
OrderBy, OrderByDescending ThenBy, ThenByDescending | 排序 |
Reverse | 反序 |
GroupBy, GroupJoin, Join | 分组和连接 |
Skip, SkipWhile | 跳过匹配的元素 |
Take, TakeWhile | 或者匹配的元素 |
Aggregate,Average,Count,LongCount Max, Min, Sum | 获得聚合值 |
Cast | 转换类型到特殊类型 |
OfType | 删除与指定类型不匹配的项 |
Except, Intersect, Union | 集合操作 |
Zip | 根据的位置执行匹配操作项目 |
Distinct | 从序列中删除重复项 |
ToArray, ToList, ToDictionary, ToLookup | 将序列转换为数组或集合 |
from子句#
from子句指定要作为数据源使用的数据集合
LINQ中from还可以包含迭代变量,迭代变量逐个表示数据源的每一个元素
from DataType item in Items
注意:
Type是集合中元素的类型,是可选的,编译器可以自行推断类型
Item是迭代变量名
Items是要查询的结合名字,集合必须是可枚举的
可以有多个from子句
实例:基础使用#
实例:使用多个from,有多个数据源 或 生成器(Multiple Generators)#
与foreach的差异:
Foreach语句需要指定每个项的顺序,而LINQ中的from并没有声明顺序
foreach语句会立即执行,而LINQ from子句只在访问该变量时执行
实例:from引用多个源#
IEnumerable<string> query = from n in numbers
from l in letters
select n.ToString() + l;
实例:from引用元素#
IEnumerable<string> query =
from fullName in fullNames
from name in fullName.Split()
select name + " came from " + fullName;
join子句#
将两个集合结合创建一个临时对象集合,每一个对象包含原始集合对象中的所有字段
注意:使用关键字equals来进行连结,不能使用==运算符
实例:
let子句#
let用于产生临时变量
let identifier = Expression
注意:
不用带变量的类型声明
可以有多个let子句
实例:
where子句#
where用于筛选数据
where BooleanExpression
注意:
这个子句是可选的
可以有多个where子句
实例:
orderby子句#
orderby子句用于结果集合排序
可选的ascending和descending关键字用于设置排序方向
注意:
orderby子句默认是升序的
可以有多个orderby子句
实例:
select子句#
select子句用于说明指定所选的对象的哪部分要被select,可以是以下部分:
数据项、数据项的某个字段、数据项中的几个字段组成的新字段
select Expression
实例:获得数据项的某个字段
var query = from s in students
select s.Name;
实例:获得数据项中的几个字段组成的新字段(匿名类型)
var query = from s in students
select new { s.Name, s.Age, s.Major};
group…by子句#
group…by子句用于设置结果集合的分组
语法:
group Expression1 by Expression2
注意:
group…by子句是可选的
分组的依据成为键(Key),可以使用Key属性进行引用
group返回的不是原始数据的可枚举类型,而是分组完成后的可枚举类型
实例:最基本的排序
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
//测试数据
var testData = new[]{
new { Name = "Panda",Age = 6666, Type = "Animal"},
new { Name = "Dog", Age = 8888, Type = "Animal"},
new { Name = "Tom", Age = 101, Type = "Man"},
new { Name = "Jame", Age = 666, Type = "Man"}
};
//分组查询
var queryResult = from n in testData
group n by n.Type;
//输出结果
foreach (var item in queryResult)
{
Console.WriteLine($"Group {item.Key}");
foreach (var detail in item)
{
Console.WriteLine($"{detail.Name} - {detail.Age} - {detail.Type}");
}
}
//wait
Console.ReadKey();
}
}
}
实例:分组排序后再对组内元素排序
List<string> animals = new List<string>()
{
"Panda", "Monkey", "Donkey",
"Dog", "Bear", "Ant", "Cow",
"Cat", "Lion", "Camel", "Elephant",
"Frog", "Fox", "Goat", "Lamb"
};
//进行分组然后排序
var result = from animal in animals
group animal by animal[0].ToString().ToUpper() into g1
orderby g1.Key //对组排序
let list2 = (from ele in g1
orderby ele.ToUpper()
select ele //对组内元素进行排序
)
select (g1.Key, list2);
//遍历进行输出
foreach (var g in result)
{
//输出组名
Console.WriteLine(g.Key);
//输出组内内容
foreach (var eleInGroup in g.list2)
{
Console.WriteLine(eleInGroup);
}
}
DISTINCT#
语法:
DISTINCT
实例:
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
//测试数据
int[] testData = new int[]
{
1,1,2,2,3,4,5,6,7,8
};
//查询
var queryResult = (from n in testData
where n < 3
select n).Distinct();
//输出结果
foreach (var item in queryResult)
{
Console.WriteLine(item);
}
//wait
Console.ReadKey();
}
}
}
聚合函数#
Count()
Min()
Max()
Average()
Sum()
方法语法(extension methods)
说明#
实例:用三种方式筛选数据#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//集合
string[] names = { "Tom", "Dick", "Harry" };
//LINQ筛选(静态方法调用形式)
IEnumerable<string> filteredNames1 =
System.Linq.Enumerable.Where(
names, n => n.Length >= 4);
//LINQ筛选(扩展方法调用形式)
IEnumerable<string> filteredNames2 =
names.Where(name => name.Length >= 4);
//LINQ筛选(运算符调用形式)
IEnumerable<string> filteredNames3 =
from name in names
where name.Length >= 4
select name;
//输出结果
//foreach (string n in filteredNames1)
//foreach (string n in filteredNames2)
foreach (string n in filteredNames3)
{
Console.Write(n + "|"); //Dick|Harry|
}
//wait
Console.ReadKey();
}
}
}
链式查询运算(Chaining Query Operators)#
链式查询的图示#
IEnumerable<string> query = names
.Where (n => n.Contains ("a"))
.OrderBy (n => n.Length)
.Select (n => n.ToUpper());
实例#
string[] names = { "Tom","Dick","Harry","Mary","Jay" };
IEnumerable<string> query = names
.Where (n => n.Contains ("a"))
.OrderBy (n => n.Length)
.Select (n => n.ToUpper());
foreach (string name in query)
Console.Write (name + "|");
// RESULT: JAY|MARY|HARRY|
标准查询运算符(Standard Query Operators)#
分类#
分类 Category | 描述 Description | 是否延迟执行 Deferred execution |
---|---|---|
Filtering | Returns a subset of elements that satisfy a given condition | Yes |
Projecting | Transforms each element with a lambda function, optionally expanding subsequences | Yes |
Joining | Meshes elements of one collection with another, using a time-efficient lookup strategy | Yes |
Ordering | Returns a reordering of a sequence | Yes |
Grouping | Groups a sequence into subsequences | Yes |
Set | Accepts two same-typed sequences, and returns their commonality, sum, or difference | Yes |
Element | Picks a single element from a sequence | No |
Aggregation | Performs a computation over a sequence, returning a scalar value (typically a number) | No |
Quantification | Performs a computation over a sequence, returning true or false | No |
Conversion: Import | Converts a nongeneric sequence to a (queryable) generic sequence | Yes |
Conversion: Export | Converts a sequence to an array, list, dictionary, or lookup, forcing immediate evaluation | No |
Generation | Manufactures a simple sequence | Yes |
Filtering operators#
Method | Description |
---|---|
Where | Returns a subset of elements that satisfy a given condition |
Take | Returns the first x elements, and discards the rest |
Skip | Ignores the first x elements, and returns the rest |
TakeWhile | Emits elements from the input sequence until the given predicate is true |
SkipWhile | Ignores elements from the input sequence until the given predicate is true and then emits the rest |
Distinct | Returns a collection that excludes duplicates |
Projection operators#
Method | Description |
---|---|
Select | Transforms each input element with a given lambda expression |
SelectMany | Transforms each input element and then flattens and concatenates the resultant subsequences |
joining operators#
Method | Description |
---|---|
Join | Applies a lookup strategy to match elements from two collections, emitting a flat result set |
GroupJoin | As above, but emits a hierarchical result set |
Zip | Enumerates two sequences in step, returning a sequence that applies a function over each element pair |
Ordering operators#
Method | Description |
---|---|
OrderBy, ThenBy | Returns the elements sorted in ascending order |
OrderByDescending, ThenByDescending | Returns the elements sorted in descending order |
Reverse | Returns the elements in reverse order |
Grouping operators#
Method | Description |
---|---|
GroupBy | Groups a sequence into subsequences |
集合运算符(Set operators)#
说明
集合运算符支持两个相同类型的集合进行运算
集合运算符主要包括:Concat 和 Union
Method | Description |
---|---|
Concat | Concatenates two sequences |
Union | Concatenates two sequences, removing duplicates |
Intersect | Returns elements present in both sequences |
Except | Returns elements present in the first sequence, but not the second |
元素操作符(Element operators)#
说明
Not all query operators return a sequence
The element operators extract one element from the input sequence
Method | Description |
---|---|
First, FirstOrDefault | Returns the first element in the sequence, or the first element satisfying a given predicate |
Last, LastOrDefault | Returns the last element in the sequence, or the last element satisfying a given predicate |
Single, SingleOrDefault | Equivalent to First/FirstOrDefault, but throws an exception if there is more than one match |
ElementAt, ElementAtOrDefault | Returns the element at the specified position |
DefaultIfEmpty | Returns a single-value sequence whose value is null or default(TSource) if the sequence has no elements |
聚合操作(Aggregation operators)#
说明
聚合操作通常返回值类型(scalar)
Method | Description |
---|---|
Count, LongCount | Returns the total number of elements in the input sequence, or the number of elements satisfying a given predicate |
Min, Max | Returns the smallest or largest element in the sequence |
Sum, Average | Calculates a numeric sum or average over elements in the sequence |
Aggregate | Performs a custom aggregation |
量词(Qualifiers)#
说明
quantifiers操作返回bool值
Method | Description |
---|---|
Contains | Returns true if the input sequence contains the given element |
Any | Returns true if any elements satisfy the given predicate |
All | Returns true if all elements satisfy the given predicate |
SequenceEqual | Returns true if the second sequence has identical elements to the input sequence |
Conversion operators (import)#
Method | Description |
---|---|
OfType | Converts IEnumerable to IEnumerable |
Cast | Converts IEnumerable to IEnumerable |
Conversion operators (export)#
Method | Description |
---|---|
ToArray | Converts IEnumerable |
ToList | Converts IEnumerable |
ToDictionary | Converts IEnumerable |
ToHashSet | Converts IEnumerable |
ToLookup | Converts IEnumerable |
AsEnumerable | Downcasts to IEnumerable |
AsQueryable | Casts or converts to IQueryable |
Generation operators#
Method | Description |
---|---|
Empty | Creates an empty sequence |
Repeat | Creates a sequence of repeating elements |
Range | Creates a sequence of integers |
方法语法概览(旧的待删除)
基础查询语句(fundamental query)#
Select#
说明#
INDEXED PROJECTION(索引)#
select表达式可选的支持一个Index值
用于表示元素当前的序列
实例:INDEXED PROJECTION
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IEnumerable<string> query = names
.Select ((s,i) => i + "=" + s); // { "0=Tom", "1=Dick", ... }
实例:
IEnumerable<string> query = from f in FontFamily.Families
select f.Name;
实例:
var query =
from f in FontFamily.Families
select new { f.Name, LineSpacing = f.GetLineSpacing (FontStyle.Bold) };
SUBQUERIES AND JOINS IN EF CORE(子查询和连接在EF Core中)#
实例:
var query =
from c in dbContext.Customers
select new {
c.Name,
Purchases = (from p in dbContext.Purchases
where p.CustomerID == c.ID && p.Price > 1000
select new { p.Description, p.Price })
.ToList()
};
实例:基础选择#
string[] names = { "Tom", "Dick", "Harry" };
IEnumerable<string> upperNames =
names.Select (n => n.ToUpper());
foreach (string n in upperNames)
{
Console.Write (n + "|"); // TOM|DICK|HARRY|
}
实例:选择多个内容#
var query = names.Select (n => new {
Name = n,
Length = n.Length
});
foreach (var row in query)
{
Console.WriteLine (row);
}
实例:筛选后再选择#
from c in dbContext.Customers
where c.Name.StartsWith ("T")
from p in c.Purchases
select new { c.Name, p.Description };
实例:多条from语句#
from c in dbContext.Customers
from p in c.Purchases
from pi in p.PurchaseItems
select new { c.Name, p.Description, pi.Detail };
实例:筛选多个元素#
from c in dbContext.Customers
from p in c.Purchases.DefaultIfEmpty()
select new {
c.Name,
Descript = p == null ? null : p.Description,
Price = p == null ? (decimal?) null : p.Price
};
SelectMany#
语法#
from identifier1 in enumerable-expression1
from identifier2 in enumerable-expression2
实例:
string[] fullNames = { "Anne Williams", "John Fred Smith", "Sue Green" };
IEnumerable<string> query = fullNames.SelectMany (name => name.Split());
foreach (string name in query)
{
Console.Write (name + "|"); // Anne|Williams|John|Fred|Smith|Sue|Green|
}
//等价于
//IEnumerable<string> query =
// from fullName in fullNames
// from name in fullName.Split()
// select name + " came from " + fullName;
Where#
说明#
实例:EF Core中的LINQ操作使用类似SQL的LIKE形式#
where EF.Functions.Like (c.Description, "%" + c.Name + "%")
实例:EF Core中的LINQ操作使用IN#
WHERE customer.Name IN ("Tom", "Jay")
实例:用三种方式筛选数据#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//集合
string[] names = { "Tom", "Dick", "Harry" };
//LINQ筛选(静态方法调用形式)
IEnumerable<string> filteredNames1 =
System.Linq.Enumerable.Where(
names, n => n.Length >= 4);
//LINQ筛选(扩展方法调用形式)
IEnumerable<string> filteredNames2 =
names.Where(name => name.Length >= 4);
//LINQ筛选(运算符调用形式)
IEnumerable<string> filteredNames3 =
from name in names
where name.Length >= 4
select name;
//输出结果
//foreach (string n in filteredNames1)
//foreach (string n in filteredNames2)
foreach (string n in filteredNames3)
{
Console.Write(n + "|"); //Dick|Harry|
}
//wait
Console.ReadKey();
}
}
}
Take#
说明#
EF Core translates Take and Skip to the ROW_NUMBER function in SQL Server 2005,
or a TOP n subquery in earlier versions of SQL Server
Take operator outputs the first x elements
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
IEnumerable<int> firstThree = numbers.Take (3);
// firstThree is { 10, 9, 8 }
实例:
IQueryable<Book> query = dbContext.Books
.Where (b => b.Title.Contains ("mercury"))
.OrderBy (b => b.Title)
.Take (20);
Skip#
说明#
Skip operator ignores the first x elements, and outputs the rest
注意:LINQ中的Skip 是从1开始计数
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
IEnumerable<int> lastTwo = numbers.Skip (3);
实例:
IQueryable<Book> query = dbContext.Books
.Where (b => b.Title.Contains ("mercury"))
.OrderBy (b => b.Title)
.Skip (20).Take (20);
EF Core注意#
注意:EF Core translates Take and Skip to the ROW_NUMBER function in SQL Server 2005,
or a TOP n subquery in earlier versions of SQL Server
Reverse#
First#
注意:如果没有找到匹配的元素会抛出异常
如果要避免异常需要使用FirstOrDefault,没有找到就会返回默认值
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
int firstNumber = numbers.First(); // 10
int firstOddNum = numbers.First(n => n % 2 == 1); // 9
Last#
注意:如果没有找到匹配的元素会抛出异常
如果要避免异常需要使用LastOrDefault,没有找到就会返回默认值
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
int lastNumber = numbers.Last(); // 6
Single#
注意:如果没有找到匹配的元素会抛出异常
如果要避免异常需要使用SingleOrDefault,没有找到就会返回默认值
Single 和 First差别
Single 和 SingleOrDefault 方法大致等同于 First 和 FirstOrDefault
差别在于Single将会抛出异常
ElementAt#
注意:如果没有找到匹配的元素会抛出异常
如果要避免异常需要使用ElementAtOrDefault,没有找到就会返回默认值
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
int secondNumber = numbers.ElementAt(2); // 8
Count#
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
int count = numbers.Count(); // 5
int evenNums = numbers.Count (n => n % 2 == 0); // 3
Min#
实例:
int min = numbers.Min(); // 6
int minRemainderAfterDivBy5 = numbers.Min(n => n % 5); // 4
Max#
实例:
int max = numbers.Max(); // 10
int maxRemainderAfterDivBy5 = numbers.Max(n => n % 5); // 4
Average#
实例:
double avg = numbers.Average(); // 8
double rms = Math.Sqrt (numbers.Average (n => n * n));
Count#
注意:
DO use System.Linq.Enumerable.Any() rather than calling patents.Count()
when checking if there are more than zero items
DO use a collection’s Count property (if available)
in favor of calling the System.Linq.Enumerable.Count() method
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
int count = numbers.Count(); // 5
int evenNums = numbers.Count (n => n % 2 == 0); // 3
Min#
实例:
int min = numbers.Min(); // 6
int minRemainderAfterDivBy5 = numbers.Min(n => n % 5); // 4
Max#
实例:
int max = numbers.Max(); // 10
int maxRemainderAfterDivBy5 = numbers.Max(n => n % 5); // 4
Average#
实例:
double avg = numbers.Average(); // 8
double rms = Math.Sqrt (numbers.Average (n => n * n));
Contains#
Contains returns true if the given element is present
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
bool hasTheNumberNine = numbers.Contains (9); // true
实例:
bool hasAThree = new int[] { 2, 3, 4 }.Contains (3); // true;
Any#
Any returns true if the given expression is true for at least one element
Calling Any without a predicate returns true if the sequence has one or more elements
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
bool hasMoreThanZeroElements = numbers.Any(); // true
bool hasOddNum = numbers.Any (n => n % 2 == 1); // true
实例:
bool hasAThree = new int[] { 2, 3, 4 }.Any (n => n == 3); // true;
实例:
bool hasABigNumber = new int[] { 2, 3, 4 }.Where (n => n > 10).Any();
实例:
from c in dbContext.Customers
where c.Purchases.Any (p => p.Price > 1000)
select c
All#
All returns true if all elements satisfy a predicate
实例:
int[] numbers = { 10, 9, 8, 7, 6 };
bool allOddNums = numbers.All (n => n % 2 == 1);
// falseint[] numbers = { 10, 9, 8, 7, 6 };
实例:
dbContext.Customers.Where (c => c.Purchases.All (p => p.Price < 100));
Concat#
运算符用于将集合添加到另一个集合
实例:
int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> concat = seq1.Concat (seq2), // { 1, 2, 3, 3, 4, 5 }
Union#
执行与Concat相同的操作,但删除重复项
实例:
int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> union = seq1.Union (seq2), // { 1, 2, 3, 4, 5 }
Intersect#
计算交集
实例:
IEnumerable<int> commonality = seq1.Intersect (seq2), // { 3 }
Except#
排除元素
实例:
IEnumerable<int>
difference1 = seq1.Except (seq2), // { 1, 2 }
difference2 = seq2.Except (seq1); // { 4, 5 }Deferred Exec
ToList#
实例:ToList操作
var numbers = new List<int>() { 1, 2 };
List<int> timesTen = numbers
.Select (n => n * 10)
.ToList(); // Executes immediately into a List<int>
numbers.Clear();
Console.WriteLine (timesTen.Count); // Still 2
```c#
## TakeWhile
TakeWhile enumerates the input sequence
emitting each item until the given predicate is false
It then ignores the remaining elements
注意:不可以用于EF Core
实例:
```c#
int[] numbers = { 3, 5, 2, 234, 4, 1 };
var takeWhileSmall = numbers.TakeWhile (n => n < 100); // { 3, 5, 2 }
SkipWhile#
SkipWhile enumerates the input sequence
ignoring each item until the given predicate is false
It then emits the remaining elements
注意:不可以用于EF Core
实例:
int[] numbers = { 3, 5, 2, 234, 4, 1 };
var skipWhileSmall = numbers.SkipWhile (n => n < 100); //{ 234, 4, 1 }
Distinct#
Distinct returns the input sequence, stripped of duplicates
实例:
char[] distinctLetters = "HelloWorld".Distinct().ToArray();
string s = new string (distinctLetters); // HeloWrd
聚合函数#
集合操作#
数据产生操作#
计数操作#
分割操作#
Zip操作#
用于将两个序列合并到一个序列中
实例:
int[] numbers = { 3, 5, 7 };
string[] words = { "three", "five", "seven", "ignored" };
IEnumerable<string> zip =
numbers.Zip (words, (n, w) => n + "=" + w);
Include#
Entity Framework Core支持早期加载(eager loading)相关的实体数据(related entities)
早期加载可以一次性加载实体相关联的其他实体的数据,避免多次查询数据库
使用include可以实现早期加载(Eager Loading)
比如使用include进行获得学生包含年级的信息:
var studentWithGrade = context.Students
.Where(s => s.FirstName == "Bill")
.Include(s => s.Grade)
.FirstOrDefault();
底层的SQL代码:
SELECT TOP(1) [s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId],[s].[LastName],
[s].[MiddleName], [s.Grade].[GradeId], [s.Grade].[GradeName], [s.Grade].[Section]
FROM [Students] AS [s]
LEFT JOIN [Grades] AS [s.Grade] ON [s].[GradeId] = [s.Grade].[GradeId]
WHERE [s].[FirstName] = N'Bill'
注意:在EF6中需要写成:
var studentWithGrade = context.Students
.Where(s => s.FirstName == "Bill")
.Include("Grade")
.FirstOrDefault();
还可以与SQL代码混用:
var studentWithGrade = context.Students
.FromSql("Select * from Students where FirstName ='Bill'")
.Include(s => s.Grade)
.FirstOrDefault();
还可以加载多个关联实体数据:
var studentWithGrade = context.Students.Where(s => s.FirstName == "Bill")
.Include(s => s.Grade)
.Include(s => s.StudentCourses)
.FirstOrDefault();
底部的SQL为:
SELECT TOP(1) [s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId], [s].[LastName],
[s].[MiddleName], [s.Grade].[GradeId], [s.Grade].[GradeName], [s.Grade].[Section]
FROM [Students] AS [s]
LEFT JOIN [Grades] AS [s.Grade] ON [s].[GradeId] = [s.Grade].[GradeId]
WHERE [s].[FirstName] = N'Bill'
ORDER BY [s].[StudentId]
Go
SELECT [s.StudentCourses].[StudentId], [s.StudentCourses].[CourseId]
FROM [StudentCourses] AS [s.StudentCourses]
INNER JOIN (
SELECT DISTINCT [t].*
FROM (
SELECT TOP(1) [s0].[StudentId]
FROM [Students] AS [s0]
LEFT JOIN [Grades] AS [s.Grade0] ON [s0].[GradeId] = [s.Grade0].[GradeId]
WHERE [s0].[FirstName] = N'Bill'
ORDER BY [s0].[StudentId]
) AS [t]
) AS [t0] ON [s.StudentCourses].[StudentId] = [t0].[StudentId]
ORDER BY [t0].[StudentId]
Go
ThenInclude#
使用ThenInclude方法可以加载多个层级的实体
注意ThenInclude方法必须在Include方法后调用
实例:
var student = context.Students.Where(s => s.FirstName == "Bill")
.Include(s => s.Grade)
.ThenInclude(g => g.Teachers)
.FirstOrDefault();
底层的SQL代码:
SELECT TOP(1) [s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId], [s].[LastName],
[s].[MiddleName], [s.Grade].[GradeId], [s.Grade].[GradeName], [s.Grade].[Section]
FROM [Students] AS [s]
LEFT JOIN [Grades] AS [s.Grade] ON [s].[GradeId] = [s.Grade].[GradeId]
WHERE [s].[FirstName] = N'Bill'
ORDER BY [s.Grade].[GradeId]
Go
SELECT [s.Grade.Teachers].[TeacherId], [s.Grade.Teachers].[GradeId], [s.Grade.Teachers].[Name]
FROM [Teachers] AS [s.Grade.Teachers]
INNER JOIN (
SELECT DISTINCT [t].*
FROM (
SELECT TOP(1) [s.Grade0].[GradeId]
FROM [Students] AS [s0]
LEFT JOIN [Grades] AS [s.Grade0] ON [s0].[GradeId] = [s.Grade0].[GradeId]
WHERE [s0].[FirstName] = N'Bill'
ORDER BY [s.Grade0].[GradeId]
) AS [t]
) AS [t0] ON [s.Grade.Teachers].[GradeId] = [t0].[GradeId]
ORDER BY [t0].[GradeId]
go
Joining(连接)#
说明
IEnumerable
主要操作:
Join Applies a lookup strategy to match elements from two collections
emitting a flat result set
GroupJoin Similar to Join, but emits a hierarchical result set
Zip Enumerates two sequences in step (like a zipper)
applying a function over each element pair
表达式语法:
from outer-var in outer-enumerable
join inner-var in inner-enumerable on outer-key-expr equals inner-key-expr
[ into identifier ]
注意:只可以用于比较相等,不可以用于比较不相等
如果需要比较不相等,使用select和selectMany
各种选择组合的效率比较图
JOIN#
The Join operator performs an inner join
emitting a flat output sequence
实例:基础使用
IQueryable<string> query =
from c in dbContext.Customers
join p in dbContext.Purchases on c.ID equals p.CustomerID
select c.Name + " bought a " + p.Description;
实例:连接不同的键
from x in sequenceX
join y in sequenceY on new { K1 = x.Prop1, K2 = x.Prop2 }
equals new { K1 = y.Prop3, K2 = y.Prop4 }
实例:使用方法形式
customers.Join ( // outer collection
purchases, // inner collection
c => c.ID, // outer key selector
p => p.CustomerID, // inner key selector
(c, p) => new
{ c.Name, p.Description, p.Price } // result selector
);
Zip#
IEnumerable
实例:基本使用
int[] numbers = { 3, 5, 7 };
string[] words = { "three", "five", "seven", "ignored" };
IEnumerable<string> zip = numbers.Zip (words, (n, w) => n + "=" + w);
实例:基本使用
string[] code = { "666", "888" };
string[] cotext = { "Panda", "Dog" };
var result = code.Zip(cotext, (c1, c2) => c2 + c1);
foreach (string item in result)
{
Console.WriteLine(item);
}
Ordering#
IEnumerable
主要操作:
OrderBy, ThenBy Sorts a sequence in ascending order
OrderByDescending, ThenByDescending Sorts a sequence in descending order
Reverse Returns a sequence in reverse order
语法:
orderby expression1 [descending] [, expression2 [descending] ... ]
实例:
IEnumerable<string> query = names.OrderBy (s => s);
实例:排序后,如果相同再次排序
IEnumerable<string> query = names.OrderBy (s => s.Length).ThenBy (s => s);
实例:排序后,如果相同再次排序多次
names.OrderBy (s => s.Length).ThenBy (s => s[1]).ThenBy (s => s[0]);
实例:降序排序,如果相同再次排序
dbContext.Purchases.OrderByDescending (p => p.Price)
.ThenBy (p => p.Description);
//等价于
//from p in dbContext.Purchases
//orderby p.Price descending, p.Description
//select p;
OrderBy和ThenBy的顺序
DO NOT call an OrderBy() following a prior OrderBy() method call
Use ThenBy() to sequence items by more than one value
Grouping(分组)#
IEnumerable
主要操作:
GroupBy Groups a sequence into subsequences
GroupBy#
注意:A where after a GroupBy is equivalent to HAVING in SQL
语法:
group element-expression by key-expression
实例:
IEnumerable<IGrouping<string,string>> query =
files.GroupBy (file => Path.GetExtension (file));
//输出
// Extension: .pdf
// -- chapter03.pdf
// -- chapter04.pdf
// Extension: .doc
// -- todo.doc
// -- menu.doc
// -- Copy of menu.doc
实例:第二个参数用于处理元素#
files.GroupBy (file => Path.GetExtension (file), file => file.ToUpper());
//输出
//Extension: .pdf
// -- CHAPTER03.PDF
// -- CHAPTER04.PDF
// Extension: .doc
// -- TODO.DOC
//对应的表达式语法
// from file in files
// group file.ToUpper() by Path.GetExtension (file);
实例:分组后再排序#
files.GroupBy (file => Path.GetExtension (file), file => file.ToUpper())
.OrderBy (grouping => grouping.Key);
实例:
IEnumerable<string> query = from vote in votes
group vote by vote into g
orderby g.Count() descending
select g.Key;
实例:使用多个Key进行分组#
from n in names
group n by new { FirstLetter = n[0], Length = n.Length };
实例:GroupBy()和组内容#
//注意:这里有个ToList()方法
var result = DbContext.Person.ToList()
.GroupBy(item => item.Age)
.Select(item => new { Key = item.Key, it = item.Select(i => i) });
//LINQ类SQL形式
//注意:这里有个ToList()方法
// var result = from item in DbContext.Person.ToList()
// group item by item.Age into temp
// select new { Key = temp.Key, it = temp.Select(t => t) };
foreach (var item in result)
{
//输出组名
Console.WriteLine(item.Key);
Console.WriteLine("=======组内容=======");
foreach (var item2 in item.it)
{
Console.WriteLine(item2.Id);
Console.WriteLine(item2.Name);
Console.WriteLine(item2.Age);
}
Console.WriteLine("=======组内容=======");
}
实例:GroupBy()和Sum()#
var result = DbContext.Person
.GroupBy(item => item.Age)
.Select(p=>new { Key = p.Key,Sum = p.Sum(p=>p.Age) });
实例:GroupBy()和Min()#
var result = DbContext.Person
.GroupBy(item => item.Age)
.Select(p=>new { Key = p.Key,Min = p.Min(p=>p.Age) });
实例:GroupBy()和Max()#
var result = DbContext.Person
.GroupBy(item => item.Age)
.Select(p=>new { Key = p.Key,Min = p.Max(p=>p.Age) });
实例:GroupBy()和Average()#
var result = DbContext.Person
.GroupBy(item => item.Age)
.Select(p=>new { Key = p.Key,Min = p.Average(p=>p.Age) });
实例:GroupBy()和Count()#
var result = DbContext.Person
.GroupBy(item => item.Age)
.Select(p=>new { Key = p.Key,Min = p.Count() });
Set Operators(集合操作)#
IEnumerable
主要操作:
Concat Returns a concatenation of elements in each of the two sequences
Union Returns a concatenation of elements in each of the two sequences
excluding duplicates
Intersect Returns elements present in both sequences
Except Returns elements present in the first, but not the second sequence
Concat#
Concat returns all the elements of the first sequence, followed by all the elements of the second
实例:
int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> concat = seq1.Concat (seq2); // { 1, 2, 3, 3, 4, 5 }
实例:合并选择的所有子项
MethodInfo[] methods = typeof (string).GetMethods();
PropertyInfo[] props = typeof (string).GetProperties();
IEnumerable<MemberInfo> both = methods.Concat<MemberInfo> (props);
实例:过滤后再合并
var methods = typeof (string).GetMethods().Where (m => !m.IsSpecialName);
var props = typeof (string).GetProperties();
var both = methods.Concat<MemberInfo> (props);
Union#
实例:
int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> union = seq1.Union (seq2); // { 1, 2, 3, 4, 5 }
Intersect#
Intersect returns the elements that two sequences have in common
实例:
int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> commonality = seq1.Intersect (seq2), // { 3 }
Except#
Except returns the elements in the first input sequence that are not present in the second
实例:
int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int>
commonality = seq1.Intersect (seq2), // { 3 }
difference1 = seq1.Except (seq2), // { 1, 2 }
difference2 = seq2.Except (seq1); // { 4, 5 }
Conversion Methods(转换方法)#
说明#
LINQ deals primarily in sequences
in other words, collections of type IEnumerable
The conversion methods convert to and from other types of collections
主要操作#
OfType Converts IEnumerable to IEnumerable
discarding wrongly typed elements
Cast Converts IEnumerable to IEnumerable
throwing an exception if there are any wrongly typed elements
ToArray Converts IEnumerable
ToList Converts IEnumerable
ToDictionary Converts IEnumerable
ToLookup Converts IEnumerable
AsEnumerable Upcasts to IEnumerable
AsQueryable Casts or converts to IQueryable
OfType#
OfType accept a nongeneric IEnumerable collection
and emit a generic IEnumerable
Cast and OfType differ in their behavior when encountering an input element that’s of an incompatible type
Cast throws an exception
OfType ignores the incompatible element
实例:
ArrayList classicList = new ArrayList(); // in System.Collections
classicList.AddRange ( new int[] { 3, 4, 5 } );
IEnumerable<int> sequence1 = classicList.OfType<int>();
实例:出现不兼容的元素对比
DateTime offender = DateTime.Now;
classicList.Add (offender);
IEnumerable<int>
sequence2 = classicList.OfType<int>(), // OK - ignores offending DateTime
sequence3 = classicList.Cast<int>(); // Throws exception
Cast#
Cast accept a nongeneric IEnumerable collection
and emit a generic IEnumerable
Cast and OfType differ in their behavior when encountering an input element that’s of an incompatible type
Cast throws an exception
OfType ignores the incompatible element
实例:
ArrayList classicList = new ArrayList(); // in System.Collections
classicList.AddRange ( new int[] { 3, 4, 5 } );
IEnumerable<int> sequence1 = classicList.Cast<int>();
实例:出现不兼容的元素对比
DateTime offender = DateTime.Now;
classicList.Add (offender);
IEnumerable<int>
sequence2 = classicList.OfType<int>(), // OK - ignores offending DateTime
sequence3 = classicList.Cast<int>(); // Throws exception
ToArray#
实例:
var range = Enumerable.Range(10, 10);
int[] array = range.ToArray();
foreach (int item in array)
{
Console.WriteLine(item);
}
ToList#
实例:
var range = Enumerable.Range(10, 10);
List<int> list = range.ToList();
foreach (int item in list)
{
Console.WriteLine(item);
}
ToDictionary#
实例:
ToHashSet#
实例:
ToLookup#
实例:
AsEnumerable#
AsEnumerable upcasts a sequence to IEnumerable
实例:
AsQueryable#
AsQueryable downcasts a sequence to IQueryable
实例:
Element Operators(元素运算符)#
说明#
IEnumerable
主要运算符#
First, FirstOrDefault
Returns the first element in the sequence, optionally satisfying a predicate
Last,LastOrDefault
Returns the last element in the sequence, optionally satisfying a predicate
Single, SingleOrDefault
Equivalent to First/FirstOrDefault
but throws an exception if there is more than one match
ElementAt, ElementAtOrDefault
Returns the element at the specified position Exception thrown
DefaultIfEmpty
Returns a single-element sequence whose value is default(TSource)
if the sequence has no elements
注意:不带default的方法,没有找到值会抛出异常
注意:带OrDefault的方法如果没有找到值会返回默认值:
null for reference type elements
false for the bool type
zero for numeric types
First#
实例:
int[] numbers = { 1, 2, 3, 4, 5 };
int first = numbers.First(); // 1
int firstEven = numbers.First (n => n % 2 == 0); // 2
Last#
实例:
int[] numbers = { 1, 2, 3, 4, 5 };
int last = numbers.Last(); // 5
int lastEven = numbers.Last (n => n % 2 == 0); // 4
Single#
实例:
int[] numbers = { 1, 2, 3, 4, 5 };
int onlyDivBy3 = numbers.Single (n => n % 3 == 0); // 3
int divBy2Err = numbers.Single (n => n % 2 == 0); // Error: 2 & 4 match
int singleError = numbers.Single (n => n > 10); // Error
int noMatches = numbers.SingleOrDefault (n => n > 10); // 0
int divBy2Error = numbers.SingleOrDefault (n => n % 2 == 0); // Error
ElementAt#
注意:
Enumerable.ElementAt is written such that if the input sequence happens to implement IList
Otherwise,it enumerates n times, and then returns the next element
ElementAt is not supported in EF Core
实例:
int[] numbers = { 1, 2, 3, 4, 5 };
int third = numbers.ElementAt (2); // 3
int tenthError = numbers.ElementAt (9); // Exception
int tenth = numbers.ElementAtOrDefault (9); // 0
DefaultIfEmpty#
DefaultIfEmpty returns a sequence containing a single element whose value is default(TSource) if the input sequence has no elements
otherwise, it returns the input sequence unchanged
实例:
ElementAtOrDefault#
Aggregation Methods(聚合方法)#
说明
IEnumerable<TSource>→scalar
主要操作:
Count, LongCount Returns the number of elements in the input sequence, optionally satisfying a predicate
Min, Max Returns the smallest or largest element in the sequence
Sum, Average Calculates a numeric sum or average over elements in the sequence
Aggregate Performs a custom aggregation
Count#
Count simply enumerates over a sequence, returning the number of items
LongCount does the same job as Count, but returns a 64-bit integer
实例:
int fullCount = new int[] { 5, 6, 7 }.Count(); // 3
实例:设置条件
int digitCount = "pa55w0rd".Count (c => char.IsDigit (c)); // 3
LongCount#
Min#
实例:
int[] numbers = { 28, 32, 14 };
int smallest = numbers.Min(); // 14;
实例:EF Core
Purchase runtimeError = dbContext.Purchases.Min (); // Error
decimal? lowestPrice = dbContext.Purchases.Min (p => p.Price); // OK
实例:EF Core多次查询
Purchase cheapest = dbContext.Purchases
.Where (p => p.Price == dbContext.Purchases.Min (p2 => p2.Price))
.FirstOrDefault();
Max#
实例:
int[] numbers = { 28, 32, 14 };
int largest = numbers.Max(); // 32;
实例:
int smallest = numbers.Max (n => n % 10); // 8;
Sum#
实例:
decimal[] numbers = { 3, 4, 8 };
decimal sumTotal = numbers.Sum(); // 15
实例:带条件
int combinedLength = names.Sum (s => s.Length); // 19
Average#
Average返回类型注意:
输入类型 返回类型
decimal decimal
float float
int, long, double double
实例:
decimal[] numbers = { 3, 4, 8 };
decimal average = numbers.Average(); // 5 (mean value)
实例:
double avg = new int[] { 3, 4 }.Average(); // 3.5
实例:EF Core结合使用
from c in dbContext.Customers
where c.Purchases.Average (p => p.Price) > 500
select c.Name;
Aggregate#
Aggregate allows you to specify a custom accumulation algorithm for implementing unusual aggregations
注意:Aggregate is not supported in EF Core and is somewhat specialized in its use cases
The first argument to Aggregate is the seed, from which accumulation starts
The second argument is an expression to update the accumulated value, given a fresh element
You can optionally supply a third argument to project the final result value from the accumulated value
实例:
int[] numbers = { 1, 2, 3 };
int sum = numbers.Aggregate (0, (total, n) => total + n); // 6
实例:
int[] numbers = { 1, 2, 3 };
int sum = numbers.Aggregate ((total, n) => total + n); // 6
实例:
int[] numbers = { 1, 2, 3 };
int x = numbers.Aggregate (0, (prod, n) => prod * n); // 0*1*2*3 = 0
int y = numbers.Aggregate ( (prod, n) => prod * n); // 1*2*3 = 6
Quantifiers#
说明#
IEnumerable
主要操作符#
Contains Returns true if the input sequence contains the given element
Any Returns true if any elements satisfy the given predicate
All Returns true if all elements satisfy the given predicate
SequenceEqual Returns true if the second sequence has identical elements to the input sequence
SequenceEqual#
SequenceEqual compares two sequences
To return true, each sequence must have identical elements in the identical order
You can optionally provide an equality comparer
the default is EqualityComparer
Generation Methods(生成方法)#
说明#
void→IEnumerable
Empty Creates an empty sequence
Repeat Creates a sequence of repeating elements
Range Creates a sequence of integers
Empty#
Empty manufactures an empty sequence and requires just a type argument
实例:
foreach (string s in Enumerable.Empty<string>())
Console.Write (s); // <nothing>
实例:
int[][] numbers =
{
new int[] { 1, 2, 3 },
new int[] { 4, 5, 6 },
null // this null makes the query below fail.
};
IEnumerable<int> flat = numbers
.SelectMany (innerArray => innerArray ?? Enumerable.Empty <int>());
foreach (int i in flat)
Console.Write (i + " "); // 1 2 3 4 5 6
Range#
Range accepts a starting index and count
实例:
foreach (int i in Enumerable.Range (5, 3))
Console.Write (i + " "); // 5 6 7
Repeat#
Repeat accepts an element to repeat, and the number of repetitions
实例:
foreach (bool x in Enumerable.Repeat (true, 3))
Console.Write (x + " "); // True True True
Remove#
删除数据的时候也可以带include()这样就可以实现递归删除
dbContext.Entity.Include(p => p.Instruments)
投影查询(Projection Query)#
除了使用Include和ThenInclude方法进行早期加载多个实体数据
还可以使用投影查询(Projection Query)
主要操作
Select Transforms each input element with the given lambda expression
SelectMany Transforms each input element,
and then flattens and concatenates the resultant subsequences
实例:
var stud = context.Students.Where(s => s.FirstName == "Bill")
.Select(s => new
{
Student = s,
Grade = s.Grade,
GradeTeachers = s.Grade.Teachers
})
.FirstOrDefault();
LINQ to Object
集合查询操作符
原理
System.Linq.Enumerable
方法
.Where()
.Select()
.Count()
.Any()
.OrderBy()
.ThenBy()
LINQ to XML
命名空间#
System.Xml.LINQ;
主要类型#
XDocument 代表XML文档
XElement 代表XML元素
XAttribute 代表XML属性
实例#
实例:使用XElement#
using System;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//LINQ对XML元素的操作
XElement products = new XElement("Products",
new XElement("Product",
new XElement("Id", 666),
new XElement("Title", "产品A"),
new XElement("Price", 66.66M)
),
new XElement("Product",
new XElement("Id", 888),
new XElement("Title", "产品B"),
new XElement("Price", 88.88M)
)
);
//筛选
var result = from product in products.Elements()
where (int)product.Element("Id") == 666
select product;
//测试输出结果
foreach (XElement xElement in result)
{
Console.WriteLine($"{xElement.Name}-{xElement.Value}");
}
//wait
Console.ReadKey();
}
}
}
实例:使用XAttribute#
using System;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//LINQ对XML元素的操作
XElement products = new XElement("Products",
new XElement("Product",
new XAttribute("Id", 666),
new XAttribute("Title", "产品A"),
new XAttribute("Price", 66.66M)
),
new XElement("Product",
new XAttribute("Id", 888),
new XAttribute("Title", "产品B"),
new XAttribute("Price", 88.88M)
)
);
//筛选
var result = from product in products.Elements()
where (int)product.Attribute("Id") == 666
select product;
//测试输出结果
foreach (XElement xElement in result)
{
Console.WriteLine($"{xElement.Name}");
foreach (XAttribute attribute in xElement.Attributes())
{
Console.WriteLine($"{attribute.Name}-{attribute.Value}");
}
}
//wait
Console.ReadKey();
}
}
}
实例:使用XNamespace#
using System;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//定义命名空间
XNamespace xns = "panda666.com";
//定义元素
XElement root = new XElement(xns + "Products",
new XElement("Product",
new XAttribute("Id", 666),
new XAttribute("Title", "产品A"),
new XAttribute("Price", 66.66M)
),
new XElement("Product",
new XAttribute("Id", 888),
new XAttribute("Title", "产品B"),
new XAttribute("Price", 88.88M)
)
);
Console.WriteLine(root);
//<Products xmlns="panda666.com">
//< Product Id = "666" Title = "产品A" Price = "66.66" xmlns = "" />
//< Product Id = "888" Title = "产品B" Price = "88.88" xmlns = "" />
//</ Products >
//wait
Console.ReadKey();
}
}
}
Parallel LINQ
实例#
Executing LINQ Queries in Parallel#
IEnumerable<string> fileList = Directory.EnumerageFiles(
rootDirectory, searchPattern);
var items = fileList.AsParallel().Select(
file =>
{
FileInfo fileInfo = new FileInfo(file);
return new
{
FileName = fileInfo.Name,
Size = fileInfo.Length
};
});
实例
LINQ to Object#
筛选-检测元素的长度小于三#
string[] tests = new string[] { "Panda", "Cat","Dog" };
IEnumerable<string> result = Enumerable.Where(tests, t => t.Length <= 3);
//IEnumerable<string> filteredNames = names.Where (n => n.Length >= 4);
foreach (string item in result)
{
Console.WriteLine(item);
}
筛选-检测元素包含a字符#
string[] tests = new string[] { "Panda", "Cat", "Dog" };
IEnumerable<string> result = tests.Where(item => item.Contains("a"));
foreach (string item in result)
{
Console.WriteLine(item);
}
筛选-排序#
string[] tests = new string[] { "Panda", "Cat", "Dog", "Monkey" };
IEnumerable<string> result = tests.Where(item => item.Length <= 3)
.OrderBy(item => item.Substring(0, 1))
//.OrderByDescending(item => item.Substring(0, 1))
.Select(item=>item);
foreach (string item in result)
{
Console.WriteLine(item);
}
选择-获得元素的长度#
string[] tests = new string[] { "Panda", "Cat" };
IEnumerable<int> result1 = tests.Select(item => item.Length);
int totalCharCount = result1.Sum();
Console.WriteLine(totalCharCount); //8
foreach (int item in result1)
{
Console.WriteLine(item);
}
提取前三个元素#
string[] tests = new string[] { "Pan", "Cat", "Pig", "Dog" };
IEnumerable<string> result = tests.Take(3);
foreach (string item in result)
{
Console.WriteLine(item);
}
跳过指定个数的元素#
string[] tests = new string[] { "Panda", "Cat", "Pig" };
IEnumerable<string> result = tests.Skip(1).Take(1);
foreach (string item in result)
{
Console.WriteLine(item); //Cat
}
反转序列的元素顺序#
string[] tests = new string[] { "Cat", "Dog", "Panda" };
IEnumerable<string> result = tests.Reverse();
foreach (string item in result)
{
Console.WriteLine(item);
}
获得第一个元素#
string[] tests = new string[] { "Panda", "Cat", "Dog" };
Console.WriteLine(tests.First());
Console.WriteLine(tests.FirstOrDefault());
获得最后一个元素#
string[] tests = new string[] { "Panda", "Cat", "Dog" };
Console.WriteLine(tests.Last());
Console.WriteLine(tests.LastOrDefault());
获得指定位置的元素#
string[] tests = new string[] { "Panda", "Cat", "Dog" };
Console.WriteLine(tests.ElementAt(1));
Console.WriteLine(tests.ElementAtOrDefault(0));
获得元素中的最大值#
int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Max());
获得元素中的最小值#
int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Min());
获得元素中的平均值#
int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Average());
获得元素中的和#
int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Sum());
获得元素个数#
int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Count());
跨Lambda表达式的变量#
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IEnumerable<string> outerQuery = names
.Where (n => n.Length == names.OrderBy (n2 => n2.Length)
.Select (n2 => n2.Length).First());
// Tom, Jay
检测是否包含某元素#
int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Contains(1)); //true
Console.WriteLine(tests.Contains(10)); //false
检测某个元素是否符合某个条件#
int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Any(item=>item > 5)); //True
检测全部元素是否符合某个条件#
int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.All(item => item > 0)); //True
连接序列#
int[] seq1 = new int[] { 1, 2, 3 };
int[] seq2 = new int[] { 3, 4, 5, 6 };
IEnumerable<int> result1 = seq1.Concat(seq2);
foreach (int item in result1)
{
Console.Write(item);
}
使用into定义变量#
var query = from n in names
select new
{
Original = n,
Vowelless = n.item
}
into temp
where temp.Vowelless.Length > 2
select temp.Original;
求两个序列的并集#
int[] seq1 = new int[] { 1, 2, 3 };
int[] seq2 = new int[] { 3, 4, 5, 6 };
IEnumerable<int> result2 = seq1.Union(seq2);
foreach (int item in result2)
{
Console.Write(item);
}
筛选出长度大于3的元素#
string[] tests = new string[] { "Panda", "Cat", "Dog", "Pig" };
IEnumerable<string> result = from item in tests
where item.Length > 3
select item;
foreach (string item in result)
{
Console.WriteLine(item); //Panda
}
LINQ基本筛选#
using System;
using System.Collections.Generic;
using System.Linq;
namespace Panda
{
class Panda
{
static void Main(string[] args)
{
int[] numbers = { 1, 2, 3, 4, 5, 6, 7 }; //对象集合
IEnumerable<int> minNumber = from i in numbers
where i <= 3
select i;
foreach (int item in minNumber)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
LINQ操作数组#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
int[] i = new int[] { 1, 2, 3, 4 };
IEnumerable<int> a = from cc in i
where cc > 2
orderby cc
select cc;
foreach (var item in a)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
LINQ数组筛选并排序#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] datas = new int[]{
1,2,3,4,5,6,7,8,9
};
var qureyResult = from item in datas
where item % 2 == 0
orderby item descending
select item;
foreach (int item in qureyResult)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
LINQ数组筛选并排序(方法形式)#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] datas = new int[]{
1,2,3,4,5,6,7,8,9
};
var qureyResult = datas.Where(x => x % 2 == 0).OrderBy(x => -x);
foreach (int item in qureyResult)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
LINQ多重排序#
使用了OrderBy之后再用ThenBy
var query = names
.Where(name => name.Length > 4)
.OrderBy(name => name.Length)
.ThenBy(name => name);
LINQ数组筛选(多条件并)#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] datas = new int[]{
1,2,3,4,5,6,7,8,9
};
var qureyResult = from item in datas
where item % 2 == 0 && item % 3 == 0
orderby item descending
select item;
foreach (int item in qureyResult)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
LINQ数组筛选(多条件并)(方法形式)#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] datas = new int[]{
1,2,3,4,5,6,7,8,9
};
var qureyResult = datas.Where(x => (x % 2 == 0 && x % 3 == 0))
.OrderBy(x => -x);
foreach (int item in qureyResult)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
LINQ数组筛选(多条件或)#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] datas = new int[]{
1,2,3,4,5,6,7,8,9
};
var qureyResult = from item in datas
where item % 2 == 0 || item % 3 == 0
orderby item descending
select item;
foreach (int item in qureyResult)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
LINQ数组筛选(多条件或)(方法形式)#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] datas = new int[]{
1,2,3,4,5,6,7,8,9
};
var qureyResult = datas.Where(x => (x % 2 == 0 || x % 3 == 0))
.OrderBy(x => -x);
foreach (int item in qureyResult)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
LINQ分组#
使用GroupBy()方法。返回值为IGrouping<TKey,TSource>类型的泛型。IGrouping对象的形式返回。IGrouping是一个继承自IEnumerable的接口。IGrouping中
Key属性表示这一组的分组数据的值。
LINQ分组#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
/// <summary>
/// 用于查询的对象
/// </summary>
class Car
{
public string CarName;
public decimal Price;
public string ProductSeries;
}
class Program
{
static void Main(string[] args)
{
//实例化一个泛型集合
List<Car> Garage = new List<Car>
{
new Car{CarName = "C1", Price = 666M, ProductSeries = "T1"},
new Car{CarName = "C2", Price = 777M, ProductSeries = "T3"},
new Car{CarName = "C3", Price = 888M, ProductSeries = "T2"},
new Car{CarName = "C4", Price = 999M, ProductSeries = "T1"},
new Car{CarName = "C5", Price = 999M, ProductSeries = "T1"},
new Car{CarName = "C6", Price = 999M, ProductSeries = "T3"}
};
//对泛型集合进行LINQ查询
var queryResult = from item in Garage
orderby item.Price
group item by item.ProductSeries;
//遍历输出集合
foreach (var g in queryResult)
{
//输出组名
Console.WriteLine("==== {0} =====", g.Key);
//输出组内容
foreach (Car car in g)
{
Console.WriteLine("The CarName is {0} and Price is {1}", car.CarName, car.Price);
}
}
//wait
Console.ReadKey();
}
}
}
LINQ分组(方法形式)#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
/// <summary>
/// 用于查询的对象
/// </summary>
class Car
{
public string CarName;
public decimal Price;
public string ProductSeries;
}
class Program
{
static void Main(string[] args)
{
//实例化一个泛型集合
List<Car> Garage = new List<Car>
{
new Car{CarName = "C1", Price = 666M, ProductSeries = "T1"},
new Car{CarName = "C2", Price = 777M, ProductSeries = "T3"},
new Car{CarName = "C3", Price = 888M, ProductSeries = "T2"},
new Car{CarName = "C4", Price = 999M, ProductSeries = "T1"},
new Car{CarName = "C5", Price = 999M, ProductSeries = "T1"},
new Car{CarName = "C6", Price = 999M, ProductSeries = "T3"}
};
//对泛型集合进行LINQ查询
var queryResult = Garage.OrderBy(x => x.Price)
.GroupBy(x => x.ProductSeries);
//遍历输出集合
foreach (var g in queryResult)
{
//输出组名
Console.WriteLine("==== {0} =====", g.Key);
//输出组内容
foreach (Car car in g)
{
Console.WriteLine("The CarName is {0} and Price is {1}", car.CarName, car.Price);
}
}
//wait
Console.ReadKey();
}
}
}
LINQ分组实例#
根据年龄分组,获取每组人数、最高工资、平均工资。
IEnumerable<IGrouping<int, Employee>> items = list.GroupBy(e => e.Age);
LINQ对分组再进行筛选#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
/// <summary>
/// 用于查询的对象
/// </summary>
class Car
{
public string CarName;
public decimal Price;
public string ProductSeries;
}
class Program
{
static void Main(string[] args)
{
//实例化一个泛型集合
List<Car> Garage = new List<Car>
{
new Car{CarName = "C1", Price = 666M, ProductSeries = "T1"},
new Car{CarName = "C2", Price = 777M, ProductSeries = "T3"},
new Car{CarName = "C3", Price = 888M, ProductSeries = "T2"},
new Car{CarName = "C4", Price = 999M, ProductSeries = "T1"},
new Car{CarName = "C5", Price = 999M, ProductSeries = "T1"},
new Car{CarName = "C6", Price = 999M, ProductSeries = "T3"}
};
//对泛型集合进行LINQ查询
var queryResult = from item in Garage
orderby item.Price
group item by item.ProductSeries into tempGroup
where tempGroup.Count() >= 2
select tempGroup;
//遍历输出集合
foreach (var g in queryResult)
{
//输出组名
Console.WriteLine("==== {0} =====", g.Key);
//输出组内容
foreach (Car car in g)
{
Console.WriteLine("The CarName is {0} and Price is {1}", car.CarName, car.Price);
}
}
//wait
Console.ReadKey();
}
}
}
LINQ使用join#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
/// <summary>
/// 汽车类
/// </summary>
class Car
{
public string CarName;
public decimal Price;
public string ProductSeries;
}
/// <summary>
/// 汽车系列类
/// </summary>
class ProductSeries
{
public string SeriesCode;
public string SeriesName;
}
class Program
{
static void Main(string[] args)
{
//实例化汽车类的泛型集合
List<Car> garage = new List<Car>
{
new Car{CarName = "C1", Price = 666M, ProductSeries = "T1"},
new Car{CarName = "C2", Price = 777M, ProductSeries = "T3"},
new Car{CarName = "C3", Price = 888M, ProductSeries = "T2"},
new Car{CarName = "C4", Price = 999M, ProductSeries = "T1"},
new Car{CarName = "C5", Price = 999M, ProductSeries = "T1"},
new Car{CarName = "C6", Price = 999M, ProductSeries = "T3"},
};
//实例化系列类的泛型集合
List<ProductSeries> productSeries = new List<ProductSeries>
{
new ProductSeries{SeriesCode = "T1", SeriesName = "豪华系列"},
new ProductSeries{SeriesCode = "T2", SeriesName = "中级系列"},
new ProductSeries{SeriesCode = "T3", SeriesName = "普通系列"}
};
//进行LINQ查询
var queryResult = from car in garage
join series in productSeries
on car.ProductSeries equals series.SeriesCode
orderby Convert.ToInt32(series.SeriesCode[1]) descending
select new { series.SeriesName, car.CarName, car.Price };
//遍历输出集合
foreach (var item in queryResult)
{
Console.WriteLine("{0} - {1} - {2}",item.SeriesName, item.CarName, item.Price);
}
//wait
Console.ReadKey();
}
}
}
LINQ使用join(方法形式)#
LINQ计算结果集个数
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[]
{
1,2,3,4,5,6,7
};
//结合使用
int queryResult = (from n in numbers
where n < 3
select n).Count();
Console.WriteLine(queryResult);
//wait
Console.ReadKey();
}
}
}
LINQ计算结果集个数(方法形式)#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] datas = new int[]{
1,2,3,4,5,6,7,8,9
};
var qureyResult = from item in datas
where item % 2 == 0
orderby item descending
select item;
//计算个数
int count = qureyResult.Count();
Console.WriteLine(count);
Console.ReadKey();
}
}
}
LINQ计算和#
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[]
{
1,2,3,4,5,6,7
};
//计算和
int queryResult = (from n in numbers
where n < 3
select n).Sum();
Console.WriteLine(queryResult);
//wait
Console.ReadKey();
}
}
}
LINQ计算平均数#
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[]
{
1,2,3,4,5,6,7
};
//计算平均数
double queryResult = (from n in numbers
where n < 3
select n).Average();
Console.WriteLine(Math.Round(queryResult,2));
//wait
Console.ReadKey();
}
}
}
LINQ计算最大值#
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[]
{
1,2,3,4,5,6,7
};
//计算最大值
int queryResult = (from n in numbers
where n < 3
select n).Max();
Console.WriteLine(queryResult);
//wait
Console.ReadKey();
}
}
}
LINQ计算最小值#
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[]
{
1,2,3,4,5,6,7
};
//计算最小值
int queryResult = (from n in numbers
where n < 3
select n).Min();
Console.WriteLine(queryResult);
//wait
Console.ReadKey();
}
}
}
LINQ去除重复数据#
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
//测试数据
int[] testData = new int[]
{
1,1,2,2,3,4,5,6,7,8
};
//查询
var queryResult = (from n in testData
where n < 3
select n).Distinct();
//输出结果
foreach (var item in queryResult)
{
Console.WriteLine(item);
}
//wait
Console.ReadKey();
}
}
}
LINQ大小写转换#
using System;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string[] words = new string[]{
"Panda","Dog","Monkey","Donkey"
};
//转为大写
var result = from word in words
select word.ToUpper();
//转为小写
var result2 = from word in words
select word.ToLower();
//测试
foreach (var item in result)
{
Console.WriteLine(item);
}
//测试
foreach (var item in result2)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
LINQ使用let定义中间变量#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
string[] animals = new string[]
{
"Panda","Monkey","Dog","Cat"
};
var queryResult = from animal in animals
let tempChars = animal.Split('n')
from item in tempChars
select item.ToUpper();
foreach (string c in queryResult)
{
Console.WriteLine(c);
}
Console.ReadKey();
}
}
}
LINQ操作泛型集合#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
/// <summary>
/// 用于查询的对象
/// </summary>
class Car
{
public string CarName;
public decimal Price;
}
class Program
{
static void Main(string[] args)
{
//实例化一个泛型集合
List<Car> Garage = new List<Car>
{
new Car{CarName = "a", Price = 666M},
new Car{CarName = "b", Price = 777M},
new Car{CarName = "c", Price = 888M},
new Car{CarName = "d", Price = 999M}
};
//对泛型集合进行LINQ查询
var ss = from item in Garage
where item.Price >= 888M
orderby item.Price
select item;
//遍历输出集合的子项
foreach (var item in ss)
{
Console.WriteLine("The CarName is {0} and Price is {1}", item.CarName, item.Price);
}
//wait
Console.ReadKey();
}
}
}
LINQ操作非泛型集合#
using System;
using System.Collections;
using System.Linq;
namespace ConsoleApp3
{
/// <summary>
/// 用于查询的对象
/// </summary>
class Car
{
public string CarName;
public decimal Price;
}
class Program
{
static void Main(string[] args)
{
//实例化一个泛型集合
ArrayList Garage = new ArrayList
{
new Car{CarName = "a", Price = 666M},
new Car{CarName = "b", Price = 777M},
new Car{CarName = "c", Price = 888M},
new Car{CarName = "d", Price = 999M}
};
//使用.OfType<T>()转换为泛型集合进行处理
//.OfType<T>()同时具有筛选功能,筛选出T类型的子项
var GarageEnum = Garage.OfType<Car>();
//对泛型集合进行LINQ查询
var ss = from item in GarageEnum
where item.Price >= 888M
orderby item.Price
select item;
//遍历输出集合的子项
foreach (var item in ss)
{
Console.WriteLine("The CarName is {0} and Price is {1}", item.CarName, item.Price);
}
Console.ReadKey();
}
}
}
LINQ查询结果转为数组#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
/// <summary>
/// 用于查询的对象
/// </summary>
class Car
{
public string CarName;
public decimal Price;
}
class Program
{
static void Main(string[] args)
{
//实例化一个泛型集合
List<Car> Garage = new List<Car>
{
new Car{CarName = "a", Price = 666M},
new Car{CarName = "b", Price = 777M},
new Car{CarName = "c", Price = 888M},
new Car{CarName = "d", Price = 999M}
};
//对泛型集合进行LINQ查询
var linqResult = from item in Garage
where item.Price >= 888M
orderby item.Price
select item;
//转为数组
Car[] searchedCar = linqResult.ToArray<Car>();
//遍历输出集合的子项
foreach (var item in searchedCar)
{
Console.WriteLine("The CarName is {0} and Price is {1}", item.CarName, item.Price);
}
Console.ReadKey();
}
}
}
LINQ查询结果转为泛型集合List#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp3
{
/// <summary>
/// 用于查询的对象
/// </summary>
class Car
{
public string CarName;
public decimal Price;
}
class Program
{
static void Main(string[] args)
{
//实例化一个泛型集合
List<Car> Garage = new List<Car>
{
new Car{CarName = "a", Price = 666M},
new Car{CarName = "b", Price = 777M},
new Car{CarName = "c", Price = 888M},
new Car{CarName = "d", Price = 999M}
};
//对泛型集合进行LINQ查询
var linqResult = from item in Garage
where item.Price >= 888M
orderby item.Price
select item;
//转为List<Car>
List<Car> searchedCar = linqResult.ToList<Car>();
//遍历输出集合的子项
foreach (var item in searchedCar)
{
Console.WriteLine("The CarName is {0} and Price is {1}", item.CarName, item.Price);
}
Console.ReadKey();
}
}
}
LINQ查询多from#
string[] animals = new string[]
{
"Panda,Dog,Cat,Monkey,Donkey",
"Duck,Cow,Forg,Rabbit,Mouse"
};
//查询
var queryResult = from item in animals
from sub in item.Split(',')
select sub;
//输出
foreach (string item in queryResult)
{
Console.WriteLine(item);
}
查找指定的记录使用Key(方法)(Entitty)#
using(PandaContext db = new PandaContext())
{
db.Products.Find(1);
}
查找指定的第一条记录使用条件(方法)#
//查找第一个数据,没有找到抛出异常
var queryResult1 = products.First();
//查找第一个数据(并筛选),没有找到抛出异常
var queryResult2 = products.First(x=>x.ProductId < 2);
//查找第一个数据,没有找到返回null
var queryResult3 = products.FirstOrDefault();
//查找第一个数据(并筛选),没有找到返回null
var queryResult4 = products.FirstOrDefault(x => x.ProductId < 2);
查找条件筛选(方法)#
var queryResult = products.Where(x => x.ProductName == "Panda");
排序(方法)#
//升序排序
var queryResult1 = products.OrderBy(x => x.ProductId);
//降序排序
var queryResult2 = products.OrderByDescending(x => x.ProductId);
再次排序(方法)
注意:必须在OrderBy或OrderByDescending后使用
//再次升序排序
var queryResult1 = products.OrderBy(x => x.ProductId).ThenBy(x=>x.ProductName);
//再次降序排序
var queryResult2 = products.OrderByDescending(x => x.ProductId).ThenByDescending(x=>x.ProductName);
降序排序#
var query = db.Person.OrderByDescending(x => x.LastName);
指定提取条数#
指定从数据库提出的数据条数
注意:并不一定返回指定的条数,有可能查询的条数少于指定的提取的条数
var queryResult = products.Where(x => x.ProductId < 100).Take(10);
指定提取条数(条件)#
//返回指定的元素(条件)
IEnumerable<string> result1 = testData.TakeWhile(x=>x.Contains("Panda"));
条件测试(任意一个条件满足)#
//任意一个满足条件返回true,否则返回false
bool result1 = testData.Any(x => x.Length > 2);
条件测试(所有条件都满足)#
//所有条件都满足返回true,否则返回false
bool result2 = testData.All(x => x.Length > 2);
获得数量(满足条件)#
//获得数量(满足条件)
int result1 = testData.Count(x => x.Length > 2);
获得数量(满足条件)(long类型)
//获得数量(满足条件)(long类型)
long result2 = testData.LongCount(x => x.Length > 2);
将元素转为指定类型#
//将元素转为指定类型
IEnumerable<string> result = testData.Cast<string>();
foreach (string item in result)
{
Console.WriteLine(item);
}
获得指定位置的元素#
//获得指定位置的元素
//注意:如果没有找到,返回类型的默认值
IEnumerable<string> result1 = testData.DefaultIfEmpty();
//指定没有找到的情况下的默认值
IEnumerable<string> result2 = testData.DefaultIfEmpty("Panda");
foreach (var item in result1)
{
Console.WriteLine(item);
}
foreach (var item in result2)
{
Console.WriteLine(item);
}
获得指定索引处的元素#
//获得指定索引处的元素
//注意:这个方法没有找到元素的情况下会抛出异常
string result1 = testData.ElementAt(0);
//没有找到情况下,返回类型的默认值
string result2 = testData.ElementAtOrDefault(10);
获得最后一个元素#
//获得最后一个元素
string result1 = testData.Last();
//获得最后一个元素(并筛选)
string result2 = testData.Last(x => x.Length > 2);
//获得最后一个元素,没有找到返回默认值
string result3 = testData.LastOrDefault();
//获得最后一个元素,没有找到返回默认值(并筛选)
string result4 = testData.LastOrDefault(x=>x.Length > 2);
返回唯一元素#
//返回唯一元素
//返回只有一个元素的序列的元素
//注意:如果不是只有一个元素将抛出异常
string result1 = testData.Single();
//指定条件
//注意:如果不是只有一个元素将抛出异常
string result2 = testData.Single(x => x.Length < 2);
//没有找到返回类型的默认值
string result3 = testData.SingleOrDefault();
string result4 = testData.SingleOrDefault(x => x.Length > 2);
连接2个序列#
//连接2个序列
IEnumerable<string> result = testData.Concat(testData2);
计算差集#
//计算差集
var result = testData.Except(testData2);
计算交集#
//计算交集
var result = testData.Intersect(testData2);
计算并集#
//计算并集
var result = testData.Union(testData2);
比较集合相等#
//比较集合相等
bool result = testData.SequenceEqual(testData2);
跳过指定的元素#
//跳过指定的元素
//跳过指定的元素(个数)
IEnumerable<string> result1 = testData.Skip(2);
//跳过指定的元素(条件)
IEnumerable<string> result2 = testData.SkipWhile(x => x.Contains("Panda"));
是否至少有一条数据#
有可能比Count()效率高。
bool b1 = list.Any(e => e.Salary > 8000);
bool b2 = list.Where(e => e.Salary > 8000).Any();
有且只有一条满足要求的数据#
list.Single(e => e.Age > 15);
最多只有一条满足要求的数据#
list.SingleOrDefault(e => e.Age > 15);
返回第一条#
list.Where(e => e.Salary > 8000).First();
返回第一条或者默认值#
list.Where(e => e.Salary > 8000).FirstOrDefault();
对数据正序排序#
list.OrderBy(e => e.Age);
倒序排序#
list.OrderByDescending(e => e.Age);
多规则排序#
可以在Order()、OrderByDescending()后继续写ThenBy()、ThenByDescending()
实例:优先按照Age排序,如果Age相同再按照Salary排序。
list.OrderBy(e => e.Age).ThenByDescending(e => e.Salary);
计算三个数值中的最大值#
int i1 = 1;
int i2 = 101;
int i3 = 100;
//计算最大值
int result = new[] { i1, i2, i3 }.Max();
统计字符出现次数#
统计一个字符串中每个字母出现的频率(忽略大小写),然
后按照从高到低的顺序输出出现频率高于2次的单词和其出
现的频率。
var items = s.Where(c => char.IsLetter(c)) //过滤非字母
.Select(c=>char.ToLower(c)) //大写字母转换为小写
.GroupBy(c=>c) //根据字母进行分组
.Where(g=>g.Count()>2) //过滤掉出现次数<=2
OrderByDescending(g=>g.Count()) //按次数排序
.Select(g=>new { Char=g.Key,Count=g.Count() });
作者:重庆熊猫
出处:https://www.cnblogs.com/cqpanda/p/16740898.html
版权:本作品采用「不论是否商业使用都不允许转载,否则按3元1字进行收取费用」许可协议进行许可。
本文来自博客园,作者:重庆熊猫,转载请注明原文链接:https://www.cnblogs.com/cqpanda/p/16740898.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库