LINQ (Language Integrated Query)直译过来—“措辞整合查询”。是 C# 中的一项主要特性,它供应了一种强大而统一的办法来查询和操作不同数据源,包括工具凑集、数据库、XML文档等。查询是一种从数据源检索数据的表达式, 传统的数据查询每每基于自身的查询语句,例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。 程序员每查询一种类型的数据源,都必须选择与之对应的查询语法,学习本钱很高。LINQ 通过将查询能力直接融入到措辞本身,查询数据就像利用类和方法一样便捷,极大地提高了代码的可读性和简洁性。
Linq事情流程
如图所示,您可以利用任何.NET支持的编程措辞编写LINQ查询,如C#、VB.NET、J#、F#等。
LINQ供应程序是位于LINQ查询和数据源之间的软件组件。LINQ供应程序将把LINQ查询转换成根本数据源可以理解的格式。例如,LINQ到SQL供应程序会将LINQ查询转换为SQL Server数据库可以理解的SQL语句。类似地,LINQ到XML供应程序将把查询转换成XML文档可以理解的格式

什么时候利用Linq查询凑集:LINQ非常适宜查询凑集,如数组、列表或任何其他实现IEnumerable的类型。它简化了过滤、排序和分组数据的过程。数据库操作:利用LINQ到SQL或实体框架,您可以实行数据库操作。LINQ查询会自动转换为SQL查询,从而更随意马虎与数据库交互,而无需编写原始SQL。可读性和可掩护性:与传统的循环和条件语句比较,LINQ查询常日会产生更具可读性和可掩护性的代码。语法是声明性的,指定您想要做什么,而不是如何做。利用XML:LINQ to XML供应了一种处理XML文档的大略而有效的方法。它许可您以更易读、更简洁的办法查询、修正和导航XML数据。连接数据源:如果您须要连接来自不同来源(如不同的凑集、数据库或XML文件)的数据,LINQ可能是一个强大的工具。它简化了连接和关联来自多个来源的数据的语法。聚合和打算:当您须要对一组项目实行打算或聚合(如总和、均匀值、最小值、最大值)时,LINQ供应了大略的方法来完成这些任务。转换数据类型:LINQ供应了将一种类型的数据转换为另一种类型的易于利用的方法,例如将数组转换为列表,反之亦然。Linq优缺陷
优点:学习Linq一种语法就查询多种数据源;代码简洁;利用visual stuodio会帮助检讨代码缺点;linq内置了很多方法来过滤/分组/聚合/求均值;代码可以复用;
缺陷:对付Linq写繁芜的SQL语句比较麻烦;没有充分发挥数据库存储过程的上风;利用Linq不恰当的时候性能很糟糕;如果查询发生变革时,须要重新编译C#代码.
查询操作的三个部分所有 LINQ 查询操作都由以下三个不同的操作组成:获取数据源; 创建查询; 实行查询。
Linq两种查询语法
查询语法(Query Expression Syntax)
查询语法类似于 SQL 查询语句(实际上我也用的不好),利用熟习的关键词(如 from、where、select、orderby、groupby、join、let、into、in、on、equals、by、ascending、descending 等)来构建查询表达式。基本语法如下
以下是一些基本示例:
using System;using System.Collections.Generic;using System.Linq;namespace LINQDemo{ class Program { static void Main(string[] args) { //Step1: Data Source List<int> integerList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; //Step2: Query //LINQ Query using Query Syntax to fetch all numbers which are > 5 var QuerySyntax = from obj in integerList //Data Source where obj > 5 //Condition select obj; //Selection //Step3: Execution foreach (var item in QuerySyntax) { Console.Write(item + " "); } Console.ReadKey(); } }}
方法语法(Method-Based Syntax)
方法语法通过调用 LINQ 扩展方法实现查询,这些方法常日采取 Lambda 表达式作为参数。虽然写法与查询语法不同,但两者在功能上完备等价。方法语法更适用于繁芜的查询条件或须要与非查询干系的 .NET 方法链式调用的情形。示例图片如下:
下面是对应上述查询语法的例子:
using System;using System.Collections.Generic;using System.Linq;namespace LINQDemo{ class Program { static void Main(string[] args) { //Step1: Data Source List<int> integerList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; //Step2: Query //LINQ Query using Query Syntax to fetch all numbers which are > 5 var QuerySyntax = integerList.Where(obj => obj > 5).ToList(); //Step3: Execution foreach (var item in QuerySyntax) { Console.Write(item + " "); } Console.ReadKey(); } }}
Linq稠浊语法
将查询语法和方法语法混用,示意图如下图所示:
示例:
List<Person> people = new List<Person>{ new Person { Name = "Alice", Age = 30, City = "New York" }, new Person { Name = "Bob", Age = 27, City = "Los Angeles" }, new Person { Name = "Charlie", Age = 3½, City = "Chicago" }, new Person { Name = "David", Age = 45, City = "San Francisco" },};var queryResult1 = from person in people where person.Age >= 30 && person.City.StartsWith("N") select new Result { FullName = $"{person.Name} ({person.Age})", Location = person.City };var queryResult2 = people.Where(p => p.Age < 30 && p.City.EndsWith(" Angeles")) .Select(p => new Result { FullName = $"{p.Name} ({p.Age})", Location = p.City });var results = queryResult1.Concat(queryResult2);foreach (var result in results){ Console.WriteLine($"{result.FullName} lives in {result.Location}");} class Person{ public string Name { get; set; } public double Age { get; set; } public string City { get; set; }}
在这个示例中:
查询语法 用于筛选年事大于即是 30 岁且城市名称以 "N" 开头的人,并将他们转换为一个新的匿名类型,包含全名(姓名+年事)和所在城市。from person in peoplewhere person.Age >= 30 && person.City.StartsWith("N")select new{ FullName = $"{person.Name} ({person.Age})", Location = person.City}
方法语法 用于筛选年事小于 30 岁且城市名称以 "Angeles" 结尾的人,并同样转换为新的匿名类型。
people.Where(p => p.Age < 30 && p.City.EndsWith(" Angeles")) .Select(p => new { FullName = $"{p.Name} ({p.Age})", Location = p.City })
稠浊语法
表示在将上述两个查询结果利用 Concat 方法合并为一个单一的结果序列:
var results = queryResult1.Concat(queryResult2);
终极的 results 变量包含了符合两个不同条件的所有人的信息。在循环中,我们遍历并打印出每个人的名字、年事和所在城市,展示了如何利用 LINQ 的稠浊语法来实行繁芜的查询操作。这种稠浊利用办法许可开拓职员根据须要选择最适宜特定查询片段的语法形式,从而保持代码的清晰度和可读性。
方法语法和查询语法比较
绝大多数时候,两种查询办法都能知足业务需求,利用那种查询取决于个人和团队偏好。
两者之间没有性能差异,由于查询语法在编译时被转换成方法语法。
对付繁芜的语法,方法查询更加强大和灵巧,但对付更大略的查询或具有SQL背景的查询,查询语法可能更直不雅观。
IEnumerable和 IQueryable
C# 中的 IEnumerable 和 IQueryable 用于保存数据凑集,并根据业务需求实行数据操作,如筛选、排序、分组等。
IEnumerable<T> 在不应用筛选器的情形下从数据库中提取记录。但是 IQueryable<T> 通过运用筛选器从数据库中提取记录。
我们先通过navicat 中通过sql脚本,在MySql数据中创建一张表,如下图所示:
我们通过c#连接上MySq,让后就可以通过下面的办法访问数据库,个中DBContext是数据库高下文类,用来配置与MySql的连接,须要利用到EF core,我会在往后的教程中专门说。
我们看怎么通过IEnumerable访问数据库:
IEnumerable<Student> listStudents = DBContext.Students.Where(x => x.Gender == "Male");
我们再来看怎么通过 IQueryable的访问数据库,和上面对比,只是做了一个IEnumerable转换为IQueryable。
IQueryable<Student> listStudents = DBContext.Students .AsQueryable() .Where(x => x.Gender == "Male");
差异
IEnumerable:紧张用于查询和操作内存中的凑集,如数组、列表和与 IEnumerable 兼容的凑集。专为查询内存中已有的数据而设计。
适用于处理全体数据集可以放入内存中的中小型内存中凑集。
IQueryable:用于从可能不在内存中的外部数据源(如数据库、Web Service 或远程数据存储)查询数据。专为查询驻留在运用程序内存之外的数据而设计。适用于处理大型数据集或运用程序外部的数据源,例如数据库。
LINQ查询的操作符映射运算符:这些运算符将序列的元素转换为新形式。常见的投影运算符包括 Select 和 SelectMany。
Select :将序列的每个元素投影到新窗体中。
SelectMany:将每个序列元素投影到 IEnumerable<T>,并将天生的序列拼展成一个序列。
过滤运算符:这些用于筛选数据。最常见的限定运算符是 Where,它将谓词运用于序列的每个元素并返回知足条件的谓词。
where:根据条件筛选一系列值。
OfType:根据指定类型筛选数组的元素。
分区运算符:这些运算符将序列分为两部分,并返回个中一部分。示例包括 Take、Skip、TakeWhile 和 SkipWhile。
Take:从序列的开头返回指天命量的连续元素。
Skip:绕过序列中指天命量的元素,然后返回别的元素。
TakeWhile:只要指定的条件为 true,则从序列中返回元素。
SkipWhile:只要指定条件为 true,就会绕过序列中的元素,然后返回别的元素。
排序运算符:这些运算符排列序列的元素。常见的排序运算符包括 OrderBy、OrderByDescending、ThenBy 和 ThenByDescending。
OrderBy:根据键按升序对序列的元素进行排序。
OrderByDescending:根据键按降序对序列的元素进行排序。
OrderByDescending:按升序对元素按顺序实行后续排序。
ThenByDescending:按降序对元素按序列实行后续排序。
Reverse:反转序列中元素的顺序。
分组运算符:这些运算符根据指定的键值对序列的元素进行分组。最值得把稳的分组运算符是 GroupBy。
GroupBy:根据指定的键选择器功能对序列的元素进行分组。
连接运算符:这些运算符用于组合来自两个或多个序列的元素。常见的联接运算符是 Join 和 GroupJoin。
Join:根据匹配的键联接两个序列。
GroupJoin:根据键对序列中的元素进行分组,并将它们与另一个序列中的元素联接。
凑集运算符:这些运算符对序列(如 Distinct、Union、Intersect 和 Except)实行数学集运算。
Distinct:从序列中删除重复元素。
Union:天生两个序列的凑集并集。
Intersect :天生两个序列的凑集交集。
Except:天生两个序列的凑集差。
转换运算符:它们用于将一种类型的序列或凑集转换为另一种类型的序列或凑集。示例包括 ToArray、ToList、ToDictionary 和 AsEnumerable。
AsEnumerable:将 IEnumerable 逼迫转换为 IEnumerable<T>。
ToArray:将序列转换为数组。
ToList:将序列转换为 List<T>。
ToDictionary :根据键选择器功能将序列转换为 Dictionary<TKey、TValue>。
元素运算符:这些运算符从序列中返回单个元素。示例包括 First、FirstOrDefault、Last、LastOrDefault、Single、SingleOrDefault 和 ElementAt。
First:返回序列的第一个元素。
FirstOrDefault:返回序列的第一个元素,如果未找到任何元素,则返回默认值。
Last:返回序列的末了一个元素。
LastOrDefault:返回序列的末了一个元素,如果未找到任何元素,则返回默认值。
Single:返回序列中的唯一元素,如果序列中没有恰好一个元素,则引发非常。
SingleOrDefault:如果序列为空,则返回序列的唯一元素或默认值;如果序列中有多个元素,此方法将引发非常。
ElementAt:返回序列中指定索引处的元素。
ElementAtOrDefault:返回序列中指定索引处的元素,如果索引超出范围,则返回默认值。
数量运算符:这些运算符返回一个布尔值,该值指示序列的所有或任何元素是否知足条件。示例包括 All、Any 和 Contains。
Any :确定序列的任何元素是否知足条件。
All:确定序列的所有元素是否都知足条件。
Contains:确定序列是否包含指定的元素。
聚合运算符:这些运算符对序列实行打算并返回单个值。示例包括 Count、Sum、Min、Max、Average 和 Aggregate。
Count:对序列中的元素进行计数。
LongCount:对序列中的元素进行计数,并将计数作为 long。
Sum:打算数值序列的总和。
Min:返回序列中的最小值。
Max:返回序列中的最大值。
Average :打算数值序列的均匀值。
Aggregate:在序列上运用累加器函数。
相等运算符:这些运算符用于比较序列的相等性。一个例子是 SequenceEqual。
SequenceEqual:通过利用元素类型的默认相等比较器来比较元素,确定两个序列是否相等。
天生操作符:这些运算符用于创建新的值序列。示例包括 Range、Repeat 和 Empty。
Empty:返回具有指定类型参数的空 IEnumerable<T>。
Repeat :天生包含一个重复值的序列。
Range:天生指定例模内的整数序列。
实例查询中涉及的实体类,没有放到本篇文章中,可以到我的代码开源仓库中下载,地址:https://gitee.com/sunny_1997/learn-English-learn-c-sharp
using Linq查询;// 初始化 Employee 凑集var employees = new List<Employee>{ new Employee(1,"张三",18,"女"), new Employee(2,"李四",28,"女"), new Employee(1,"无法",18,"女"), new Employee(2,"两列四",98, "男"), new Employee(1,"刘是否",4,"女"), new Employee(2,"赵佳佳",28, "男"), new Employee(1,"孙行者",38, "男"), new Employee(2,"程家山",19, "男"), // ... 其他员工 ...};// 查询所熟年龄大于 25 岁的员工姓名var namesOfOlderEmployees = from e in employees where e.Age > 25 select e.Name;// 对员工按年事降序排列var employeesOrderedByAge = from e in employees orderby e.Age descending select e;// 分组员工按性别,并打算每个组的均匀年事var averageAgesByGender = from e in employees group e by e.Gender into g select new { Gender = g.Key, AverageAge = g.Average(e => e.Age) };List<Book> books = new List<Book>();books.Add(new Book { id = Guid.NewGuid(), name = "西游记", price = 25.0f });books.Add(new Book { id = Guid.NewGuid(), name = "红楼梦", price = 35.1f });books.Add(new Book { id = Guid.NewGuid(), name = "水浒传", price = 15.0f });books.Add(new Book { id = Guid.NewGuid(), name = "三国演义", price = 34.0f });books.Add(new Book { id = Guid.NewGuid(), name = "三体", price = 55.7f });books.Add(new Book { id = Guid.NewGuid(), name = "我的朋友叫安妮", price = 4.0f });books.Add(new Book { id = Guid.NewGuid(), name = "隔壁的胡安", price = 15.7f });books.Add(new Book { id = Guid.NewGuid(), name = "老家的柳树", price = 20f });{ var result1 = books.Where(b => b.price < 21).Select(b => b); var results2 = books.Select(b => b.price < 21); var results3 = books.Where(b => b.price < 30).Select(b => new { Id = b.id ,Name = b.name}) .OrderBy(b=>b.Name); }List<Shoes> shoes = new List<Shoes>();shoes.Add(new Shoes(Guid.NewGuid(),"ANTA",78));var result3 = books.Filter(new Func<Book, bool>( b =>b.price>20));//利用List:把稳要把lambda表达式用小括号括起来var result4= books.Filter2(new Func<Book, bool>(b => b.price > 20)); //利用IEnumerable://把稳要把lambda表达式用小括号括起来foreach (var item in result4){ Console.WriteLine(item.name);}List<Person> people = new List<Person>{ new Person { Name = "Alice", Age = 30, City = "New York" }, new Person { Name = "Bob", Age = 27, City = "Los Angeles" }, new Person { Name = "Charlie", Age = 3, City = "Chicago" }, new Person { Name = "David", Age = 45, City = "San Francisco" },};// 稠浊语法示例var queryResult1 = from person in people where person.Age >= 30 && person.City.StartsWith("N") select new Result { FullName = $"{person.Name} ({person.Age})", Location = person.City };var queryResult2 = people.Where(p => p.Age < 30 && p.City.EndsWith(" Angeles")) .Select(p => new Result { FullName = $"{p.Name} ({p.Age})", Location = p.City });var results = queryResult1.Concat(queryResult2);foreach (var result in results){ Console.WriteLine($"{result.FullName} lives in {result.Location}");}List<int> intList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//Method Syntaxvar OddNumbersWithIndexPosition = intList.Select((num, index) => new { Numbers = num, IndexPosition = index }).Where(x => x.Numbers % 2 != 0) .Select(data => new { Number = data.Numbers, IndexPosition = data.IndexPosition }); foreach (var item in OddNumbersWithIndexPosition){ Console.WriteLine($"IndexPosition :{item.IndexPosition} , Value : {item.Number}");}var a = new{ FirstName = "John", LastName = "Doe", Age = 30, IsEmployed = true};Console.WriteLine(a.FirstName);