LINQ 快速指南
LINQ - 概述
全世界的开发者都曾经在数据查询方面遇到问题,因为缺乏明确的路径,并且需要掌握多种技术,例如 SQL、Web 服务、XQuery 等。
LINQ(语言集成查询)由 Anders Hejlsberg 设计,在 Visual Studio 2008 中引入,允许编写查询而无需了解 SQL、XML 等查询语言。LINQ 查询可以编写用于各种数据类型。
LINQ 查询示例
C#
using System; using System.Linq; class Program { static void Main() { string[] words = {"hello", "wonderful", "LINQ", "beautiful", "world"}; //Get only short words var shortWords = from word in words where word.Length <= 5 select word; //Print each word out foreach (var word in shortWords) { Console.WriteLine(word); } Console.ReadLine(); } }
VB
Module Module1 Sub Main() Dim words As String() = {"hello", "wonderful", "LINQ", "beautiful", "world"} ' Get only short words Dim shortWords = From word In words _ Where word.Length <= 5 _ Select word ' Print each word out. For Each word In shortWords Console.WriteLine(word) Next Console.ReadLine() End Sub End Module
当编译并执行上述 C# 或 VB 代码时,将产生以下结果:
hello LINQ world
LINQ 的语法
LINQ 有两种语法。它们如下所示。
Lambda(方法)语法
var longWords = words.Where( w ⇒ w.length > 10); Dim longWords = words.Where(Function(w) w.length > 10)
查询(理解)语法
var longwords = from w in words where w.length > 10; Dim longwords = from w in words where w.length > 10
LINQ 的类型
LINQ 的类型简述如下。
- LINQ to Objects
- LINQ to XML(XLINQ)
- LINQ to DataSet
- LINQ to SQL (DLINQ)
- LINQ to Entities
除了上述内容外,还有一种名为 PLINQ 的 LINQ 类型,它是 Microsoft 的并行 LINQ。
.NET 中的 LINQ 架构
LINQ 在 .NET 中采用三层架构,最上层由语言扩展组成,底层由数据源组成,这些数据源通常是实现 IEnumerable <T> 或 IQueryable <T> 通用接口的对象。架构如下所示。
查询表达式
查询表达式只不过是以类似于 SQL 的形式表达的 LINQ 查询,使用 Select、Where 和 OrderBy 等查询运算符。查询表达式通常以关键字“From”开头。
要访问标准 LINQ 查询运算符,默认情况下应导入命名空间 System.Query。这些表达式写在声明性查询语法中,这是 C# 3.0。
以下是一个示例,演示完整的查询操作,其中包括数据源创建、查询表达式定义和查询执行。
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Operators { class LINQQueryExpressions { static void Main() { // Specify the data source. int[] scores = new int[] { 97, 92, 81, 60 }; // Define the query expression. IEnumerable<int> scoreQuery = from score in scores where score > 80 select score; // Execute the query. foreach (int i in scoreQuery) { Console.Write(i + " "); } Console.ReadLine(); } } }
当编译并执行上述代码时,将产生以下结果:
97 92 81
扩展方法
扩展方法是在 .NET 3.5 中引入的,仅在静态类中声明,允许将自定义方法添加到对象以执行一些精确的查询操作,从而扩展类而无需成为该类的实际成员。这些也可以重载。
简而言之,扩展方法用于将查询表达式转换为传统的元方法调用(面向对象)。
LINQ 与存储过程的区别
LINQ 与存储过程之间存在许多差异。这些差异如下所述。
存储过程比 LINQ 查询快得多,因为它们遵循预期的执行计划。
与存储过程相比,执行 LINQ 查询更容易避免运行时错误,因为前者具有 Visual Studio 的 IntelliSense 支持以及编译时的完整类型检查。
LINQ 允许使用 .NET 调试器进行调试,而存储过程则不行。
LINQ 支持多个数据库,而存储过程则需要为不同类型的数据库重写代码。
与部署一组存储过程相比,部署基于 LINQ 的解决方案更加容易和简单。
LINQ 的需求
在 LINQ 之前,需要学习 C#、SQL 和将两者结合在一起形成完整应用程序的各种 API。由于这些数据源和编程语言存在阻抗不匹配;因此,需要简短的编码。
以下是一个示例,说明在 LINQ 出现之前,开发人员在查询数据时使用了多少种不同的技术。
SqlConnection sqlConnection = new SqlConnection(connectString); SqlConnection.Open(); System.Data.SqlClient.SqlCommand sqlCommand = new SqlCommand(); sqlCommand.Connection = sqlConnection; sqlCommand.CommandText = "Select * from Customer"; return sqlCommand.ExecuteReader (CommandBehavior.CloseConnection)
有趣的是,在特色代码行中,查询仅由最后两行定义。使用 LINQ,可以在更短的时间内以可读的彩色编码形式编写相同的数据查询,如下所示。
Northwind db = new Northwind(@"C:\Data\Northwnd.mdf"); var query = from c in db.Customers select c;
LINQ 的优势
LINQ 提供了许多优势,其中最重要的是其强大的表达能力,使开发人员能够声明性地表达。LINQ 的其他一些优势如下所示。
LINQ 提供语法突出显示,有助于在设计时查找错误。
LINQ 提供 IntelliSense,这意味着可以轻松编写更准确的查询。
在 LINQ 中编写代码的速度非常快,因此开发时间也大大减少。
由于 LINQ 集成到 C# 语言中,因此可以轻松进行调试。
由于 LINQ 的分层特性,查看两个表之间的关系很容易,这使得能够在更短的时间内组合连接多个表的查询。
LINQ 允许在查询许多不同的数据源时使用单个 LINQ 语法,这主要是因为其统一的基础。
LINQ 是可扩展的,这意味着可以使用 LINQ 知识来查询新的数据源类型。
LINQ 提供在单个查询中连接多个数据源以及将复杂问题分解为易于调试的一组简短查询的功能。
LINQ 提供了一种将一种数据类型转换为另一种数据类型(例如将 SQL 数据转换为 XML 数据)的简单转换方法。
LINQ - 环境设置
在开始使用 LINQ 程序之前,最好先了解设置 LINQ 环境的细微之处。LINQ 需要 .NET Framework,这是一个革命性的平台,可以拥有各种各样的应用程序。可以使用 C# 或 Visual Basic 方便地编写 LINQ 查询。
Microsoft 通过 Visual Studio 提供这两种语言(即 C# 和 Visual Basic)的工具。我们的示例都在 Visual Studio 2010 中编译和编写。但是,Visual Basic 2013 版本也可供使用。它是最新版本,与 Visual Studio 2012 具有许多相似之处。
在 Windows 7 上安装 Visual Studio 2010
Visual Studio 可以从安装介质(如 DVD)安装。成功在系统上安装 Visual Basic 2010 需要管理员凭据。在安装之前,务必断开所有可移动 USB 设备与系统的连接,否则安装可能会失败。安装所需的一些硬件要求如下。
硬件要求
- 1.6 GHz 或更高
- 1 GB RAM
- 3 GB(可用硬盘空间)
- 5400 RPM 硬盘驱动器
- 兼容 DirectX 9 的显卡
- DVD-ROM 驱动器
安装步骤
步骤 1 - 首先插入包含 Visual Studio 2010 软件包的 DVD,然后单击屏幕上弹出框中显示的“安装或从您的媒体运行程序”。
步骤 2 - 现在将显示 Visual Studio 的安装程序。选择“安装 Microsoft Visual Studio 2010”。
步骤 3 - 单击后,过程将启动,并在屏幕上显示一个安装窗口。加载安装组件(需要一些时间)完成后,单击“下一步”按钮进入下一步。
步骤 4 - 这是安装的最后一步,将出现一个起始页,只需选择“我已阅读并接受许可条款”,然后单击“下一步”按钮。
步骤 5 - 现在从屏幕上显示的选项页面中选择要安装的功能。您可以选择“完全”或“自定义”选项。如果您的磁盘空间小于磁盘空间要求中显示的所需空间,请选择自定义选项。
步骤 6 - 选择自定义选项时,将出现以下窗口。选择要安装的功能,然后单击“更新”,否则转到步骤 7。但是,建议不要选择自定义选项,因为将来您可能需要您选择不安装的功能。
步骤 7 - 很快将显示一个弹出窗口,安装将开始,这可能需要很长时间。请记住,这是安装所有组件。
步骤 8 - 最后,您将能够在窗口中查看一条消息,表明安装已成功完成。单击“完成”。
在 Visual Studio 2010 中使用 LINQ 编写 C# 程序
启动 Visual Studio 2010 Ultimate 版本,然后从菜单中选择文件,然后选择新建项目。
一个新的项目对话框将出现在您的屏幕上。
现在选择 Visual C# 作为已安装模板下的类别,然后选择控制台应用程序模板,如下图所示。
在底部的名称框中为您的项目命名,然后按确定。
新的项目将出现在屏幕上新的对话框的右侧的解决方案资源管理器中。
现在从解决方案资源管理器中选择 Program.cs,您可以在编辑器窗口中查看代码,该代码以“using System”开头。
在这里,您可以开始编写以下 C# 程序。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HelloWorld { class Program { static void Main(string[] args) { Console.WriteLine("Hello World") Console.ReadKey(); } } }
按 F5 键运行您的项目。强烈建议在运行项目之前选择“文件”→“全部保存”保存项目。
在 Visual Studio 2010 中使用 LINQ 编写 VB 程序
启动 Visual Studio 2010 Ultimate 版本,然后从菜单中选择文件,然后选择新建项目。
一个新的项目对话框将出现在您的屏幕上。
现在选择 Visual Basic 作为已安装模板下的类别,然后选择控制台应用程序模板。
在底部的名称框中为您的项目命名,然后按确定。
您将看到一个包含 Module1.vb 的屏幕。在这里开始使用 LINQ 编写 VB 代码。
Module Module1 Sub Main() Console.WriteLine("Hello World") Console.ReadLine() End Sub End Module
按 F5 键运行您的项目。强烈建议在运行项目之前选择“文件”→“全部保存”保存项目。
当编译并运行上述 C# 或 VB 代码时,将产生以下结果:
Hello World
LINQ - 查询运算符
一组构成查询模式的扩展方法称为 LINQ 标准查询运算符。作为 LINQ 查询表达式的构建块,这些运算符提供了各种查询功能,例如筛选、排序、投影、聚合等。
根据其功能,LINQ 标准查询运算符可以分为以下几类。
- 筛选运算符
- 连接运算符
- 投影操作
- 排序操作符
- 分组操作符
- 转换
- 连接
- 聚合
- 量词操作
- 分区操作
- 生成操作
- 集合操作
- 相等性
- 元素操作符
筛选运算符
筛选是一种限制结果集的操作,使其只包含满足特定条件的选定元素。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
where | 基于谓词函数筛选值 | where | Where |
OfType | 基于值是否可以转换为指定类型来筛选值 | 不适用 | 不适用 |
连接运算符
连接是指对数据源进行操作,这些数据源之间存在难以直接追踪的关系。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
Join | 该操作符基于匹配的键连接两个序列 | join … in … on … equals … | From x In …, y In … Where x.a = y.a |
GroupJoin | 连接两个序列并分组匹配的元素 | join … in … on … equals … into … | Group Join … In … On … |
投影操作
投影是一种将对象转换为具有特定属性的全新形式的操作。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
Select | 该操作符基于转换函数投影值 | select | Select |
SelectMany | 该操作符投影基于转换函数的数值序列,并将它们展平为单个序列 | 使用多个 from 子句 | 使用多个 From 子句 |
排序操作符
排序操作允许基于一个或多个属性对序列的元素进行排序。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
OrderBy | 该操作符按升序排序值 | orderby | Order By |
OrderByDescending | 该操作符按降序排序值 | orderby ... descending | Order By ... Descending |
ThenBy | 执行二次升序排序 | orderby …, … | Order By …, … |
ThenByDescending | 执行二次降序排序 | orderby …, … descending | Order By …, … Descending |
Reverse | 反转集合中元素的顺序 | 不适用 | 不适用 |
分组操作符
这些操作符基于共同的共享属性将数据分成几组。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
GroupBy | 将项目序列组织成组,并将其作为 IGrouping |
group … by -or- group … by … into … | Group … By … Into … |
ToLookup | 执行分组操作,返回键值对序列 | 不适用 | 不适用 |
转换
这些操作符更改输入对象的类型,并用于各种应用程序。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
AsEnumerable | 返回类型为 IEnumerable |
不适用 | 不适用 |
AsQueryable | 将 (泛型) IEnumerable 转换为 (泛型) IQueryable | 不适用 | 不适用 |
Cast | 将集合的元素强制转换为指定类型 | 使用显式类型的范围变量。例如:from string str in words | From … As … |
OfType | 基于值能否转换为特定类型来筛选值 | 不适用 | 不适用 |
ToArray | 强制执行查询并将集合转换为数组 | 不适用 | 不适用 |
ToDictionary | 基于键选择器函数将元素设置为 Dictionary |
不适用 | 不适用 |
ToList | 通过将集合转换为 List |
不适用 | 不适用 |
ToLookup | 强制执行查询,并基于键选择器函数将元素放入 Lookup |
不适用 | 不适用 |
连接
执行两个序列的连接,其操作与 Union 操作符非常相似,区别在于此操作不删除重复项。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
Concat | 连接两个序列以形成一个序列。 | 不适用 | 不适用 |
聚合
执行任何类型的所需聚合,并允许在 LINQ 中创建自定义聚合。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
Aggregate | 对集合的值进行操作以执行自定义聚合操作 | 不适用 | 不适用 |
Average | 计算值集合的平均值 | 不适用 | Aggregate … In … Into Average() |
Count | 计算集合中满足谓词函数的元素个数 | 不适用 | Aggregate … In … Into Count() |
LongCount | 计算大型集合中满足谓词函数的元素个数 | 不适用 | Aggregate … In … Into LongCount() |
Max | 查找集合中的最大值 | 不适用 | Aggregate … In … Into Max() |
Min | 查找集合中的最小值 | 不适用 | Aggregate … In … Into Min() |
Sum | 查找集合中值的总和 | 不适用 | Aggregate … In … Into Sum() |
量词操作
这些操作符在序列中的一些或所有元素满足特定条件时返回布尔值,即 True 或 False。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
All | 如果序列的所有元素都满足谓词条件,则返回“True”值 | 不适用 | Aggregate … In … Into All(…) |
Any | 通过搜索序列来确定序列中的任何元素是否满足指定条件 | 不适用 | Aggregate … In … Into Any() |
Contains | 如果找到序列中存在特定元素,则返回“True”值;如果序列不包含该特定元素,则返回“false”值 | 不适用 | 不适用 |
分区操作符
将输入序列分成两个单独的部分,而不重新排列序列的元素,然后返回其中一个部分。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
Skip | 跳过序列中指定数量的元素,并返回其余元素 | 不适用 | Skip |
SkipWhile | 与 Skip 相同,唯一的例外是跳过的元素数量由布尔条件指定 | 不适用 | Skip While |
Take | 从序列中获取指定数量的元素,并跳过其余元素 | 不适用 | Take |
TakeWhile | 与 Take 相同,只是获取的元素数量由布尔条件指定 | 不适用 | Take While |
生成操作
生成操作符创建新的值序列。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
DefaultIfEmpty | 应用于空序列时,在序列中生成默认元素 | 不适用 | 不适用 |
Empty | 返回空值序列,是最简单的生成操作符 | 不适用 | 不适用 |
Range | 生成包含整数或数字序列的集合 | 不适用 | 不适用 |
Repeat | 生成包含特定长度重复值的序列 | 不适用 | 不适用 |
集合操作
集合操作共有四个操作符,每个操作符根据不同的标准产生结果。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
Distinct | 通过过滤重复数据(如有)从集合中返回唯一值的列表 | 不适用 | Distinct |
Except | 比较两个集合的值,并返回一个集合中不在另一个集合中的值 | 不适用 | 不适用 |
Intersect | 返回在两个单独集合中发现相同的数值集合 | 不适用 | 不适用 |
Union | 将两个不同集合的内容组合成一个列表,并且不包含任何重复内容 | 不适用 | 不适用 |
相等性
比较两个句子(可枚举的)并确定它们是否完全匹配。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
SequenceEqual | 如果发现两个序列彼此相同,则返回布尔值 | 不适用 | 不适用 |
元素操作符
除了 DefaultIfEmpty 之外,其余八个标准查询元素操作符都从集合中返回单个元素。
操作符 | 描述 | C# 查询表达式语法 | VB 查询表达式语法 |
---|---|---|---|
ElementAt | 返回集合中特定索引处的元素 | 不适用 | 不适用 |
ElementAtOrDefault | 与 ElementAt 相同,只是在特定索引超出范围的情况下也返回默认值 | 不适用 | 不适用 |
First | 检索集合中的第一个元素或满足特定条件的第一个元素 | 不适用 | 不适用 |
FirstOrDefault | 与 First 相同,只是在不存在此类元素的情况下也返回默认值 | 不适用 | 不适用 |
Last | 检索集合中的最后一个元素或满足特定条件的最后一个元素 | 不适用 | 不适用 |
LastOrDefault | 与 Last 相同,只是在不存在任何此类元素的情况下也返回默认值 | 不适用 | 不适用 |
Single | 返回集合的单个元素或满足特定条件的单个元素 | 不适用 | 不适用 |
SingleOrDefault | 与 Single 相同,只是在不存在任何此类单个元素的情况下也返回默认值 | 不适用 | 不适用 |
DefaultIfEmpty | 如果集合或列表为空或为 null,则返回默认值 | 不适用 | 不适用 |
LINQ - SQL
LINQ to SQL 提供了一个基础结构(运行时)来将关系数据作为对象进行管理。它是 .NET Framework 3.5 版的一个组件,能够将对象模型的语言集成查询转换为 SQL。然后将这些查询发送到数据库以执行。从数据库获得结果后,LINQ to SQL 又将其转换为对象。
LINQ To SQL 简介
对于大多数 ASP.NET 开发人员来说,LINQ to SQL(也称为 DLINQ)是语言集成查询中令人兴奋的一部分,因为它允许使用常用的 LINQ 表达式查询 SQL Server 数据库中的数据。它也允许更新、删除和插入数据,但它唯一的缺点是它仅限于 SQL Server 数据库。但是,与 ADO.NET 相比,LINQ to SQL 有许多好处,例如降低复杂性、减少代码行数等等。
下图显示了 LINQ to SQL 的执行架构。
如何使用 LINQ to SQL?
步骤 1 − 与数据库服务器建立新的“数据连接”。查看 &arrar; 服务器资源管理器 &arrar; 数据连接 &arrar; 添加连接
步骤 2 − 添加 LINQ To SQL 类文件
步骤 3 − 从数据库中选择表并将其拖放到新的 LINQ to SQL 类文件中。
步骤 4 − 将表添加到类文件中。
使用 LINQ to SQL 查询
使用 LINQ to SQL 执行查询的规则与标准 LINQ 查询类似,即查询是延迟执行还是立即执行。有各种组件参与 LINQ to SQL 查询的执行,这些组件如下。
LINQ to SQL API − 代表应用程序请求查询执行,并将其发送到 LINQ to SQL 提供程序。
LINQ to SQL 提供程序 − 将查询转换为 Transact SQL(T-SQL),并将新查询发送到 ADO 提供程序以执行。
ADO 提供程序 − 查询执行后,将结果以 DataReader 的形式发送到 LINQ to SQL 提供程序,后者将其转换为用户对象的形式。
需要注意的是,在执行 LINQ to SQL 查询之前,必须通过 DataContext 类连接到数据源。
使用 LINQ To SQL 进行插入、更新和删除
添加或插入
C#
using System; using System.Linq; namespace LINQtoSQL { class LinqToSQLCRUD { static void Main(string[] args) { string connectString = System.Configuration.ConfigurationManager.ConnectionStrings["LinqToSQLDBConnectionString"].ToString(); LinqToSQLDataContext db = new LinqToSQLDataContext(connectString); //Create new Employee Employee newEmployee = new Employee(); newEmployee.Name = "Michael"; newEmployee.Email = "[email protected]"; newEmployee.ContactNo = "343434343"; newEmployee.DepartmentId = 3; newEmployee.Address = "Michael - USA"; //Add new Employee to database db.Employees.InsertOnSubmit(newEmployee); //Save changes to Database. db.SubmitChanges(); //Get new Inserted Employee Employee insertedEmployee = db.Employees.FirstOrDefault(e ⇒e.Name.Equals("Michael")); Console.WriteLine("Employee Id = {0} , Name = {1}, Email = {2}, ContactNo = {3}, Address = {4}", insertedEmployee.EmployeeId, insertedEmployee.Name, insertedEmployee.Email, insertedEmployee.ContactNo, insertedEmployee.Address); Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
VB
Module Module1 Sub Main() Dim connectString As String = System.Configuration.ConfigurationManager.ConnectionStrings("LinqToSQLDBConnectionString").ToString() Dim db As New LinqToSQLDataContext(connectString) Dim newEmployee As New Employee() newEmployee.Name = "Michael" newEmployee.Email = "[email protected]" newEmployee.ContactNo = "343434343" newEmployee.DepartmentId = 3 newEmployee.Address = "Michael - USA" db.Employees.InsertOnSubmit(newEmployee) db.SubmitChanges() Dim insertedEmployee As Employee = db.Employees.FirstOrDefault(Function(e) e.Name.Equals("Michael")) Console.WriteLine("Employee Id = {0} , Name = {1}, Email = {2}, ContactNo = {3}, Address = {4}", insertedEmployee.EmployeeId, insertedEmployee.Name, insertedEmployee.Email, insertedEmployee.ContactNo, insertedEmployee.Address) Console.WriteLine(vbLf & "Press any key to continue.") Console.ReadKey() End Sub End Module
编译并运行上述 C# 或 VB 代码后,将产生以下结果:
Emplyee ID = 4, Name = Michael, Email = [email protected], ContactNo = 343434343, Address = Michael - USA Press any key to continue.
更新
C#
using System; using System.Linq; namespace LINQtoSQL { class LinqToSQLCRUD { static void Main(string[] args) { string connectString = System.Configuration.ConfigurationManager.ConnectionStrings["LinqToSQLDBConnectionString"].ToString(); LinqToSQLDataContext db = new LinqToSQLDataContext(connectString); //Get Employee for update Employee employee = db.Employees.FirstOrDefault(e =>e.Name.Equals("Michael")); employee.Name = "George Michael"; employee.Email = "[email protected]"; employee.ContactNo = "99999999"; employee.DepartmentId = 2; employee.Address = "Michael George - UK"; //Save changes to Database. db.SubmitChanges(); //Get Updated Employee Employee updatedEmployee = db.Employees.FirstOrDefault(e ⇒e.Name.Equals("George Michael")); Console.WriteLine("Employee Id = {0} , Name = {1}, Email = {2}, ContactNo = {3}, Address = {4}", updatedEmployee.EmployeeId, updatedEmployee.Name, updatedEmployee.Email, updatedEmployee.ContactNo, updatedEmployee.Address); Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
VB
Module Module1 Sub Main() Dim connectString As String = System.Configuration.ConfigurationManager.ConnectionStrings("LinqToSQLDBConnectionString").ToString() Dim db As New LinqToSQLDataContext(connectString) Dim employee As Employee = db.Employees.FirstOrDefault(Function(e) e.Name.Equals("Michael")) employee.Name = "George Michael" employee.Email = "[email protected]" employee.ContactNo = "99999999" employee.DepartmentId = 2 employee.Address = "Michael George - UK" db.SubmitChanges() Dim updatedEmployee As Employee = db.Employees.FirstOrDefault(Function(e) e.Name.Equals("George Michael")) Console.WriteLine("Employee Id = {0} , Name = {1}, Email = {2}, ContactNo = {3}, Address = {4}", updatedEmployee.EmployeeId, updatedEmployee.Name, updatedEmployee.Email, updatedEmployee.ContactNo, updatedEmployee.Address) Console.WriteLine(vbLf & "Press any key to continue.") Console.ReadKey() End Sub End Module
编译并运行上述 C# 或 Vb 代码后,将产生以下结果:
Emplyee ID = 4, Name = George Michael, Email = [email protected], ContactNo = 999999999, Address = Michael George - UK Press any key to continue.
删除
C#
using System; using System.Linq; namespace LINQtoSQL { class LinqToSQLCRUD { static void Main(string[] args) { string connectString = System.Configuration.ConfigurationManager.ConnectionStrings["LinqToSQLDBConnectionString"].ToString(); LinqToSQLDataContext db = newLinqToSQLDataContext(connectString); //Get Employee to Delete Employee deleteEmployee = db.Employees.FirstOrDefault(e ⇒e.Name.Equals("George Michael")); //Delete Employee db.Employees.DeleteOnSubmit(deleteEmployee); //Save changes to Database. db.SubmitChanges(); //Get All Employee from Database var employeeList = db.Employees; foreach (Employee employee in employeeList) { Console.WriteLine("Employee Id = {0} , Name = {1}, Email = {2}, ContactNo = {3}", employee.EmployeeId, employee.Name, employee.Email, employee.ContactNo); } Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
VB
Module Module1 Sub Main() Dim connectString As String = System.Configuration.ConfigurationManager.ConnectionStrings("LinqToSQLDBConnectionString").ToString() Dim db As New LinqToSQLDataContext(connectString) Dim deleteEmployee As Employee = db.Employees.FirstOrDefault(Function(e) e.Name.Equals("George Michael")) db.Employees.DeleteOnSubmit(deleteEmployee) db.SubmitChanges() Dim employeeList = db.Employees For Each employee As Employee In employeeList Console.WriteLine("Employee Id = {0} , Name = {1}, Email = {2}, ContactNo = {3}", employee.EmployeeId, employee.Name, employee.Email, employee.ContactNo) Next Console.WriteLine(vbLf & "Press any key to continue.") Console.ReadKey() End Sub End Module
编译并运行上述 C# 或 VB 代码后,将产生以下结果:
Emplyee ID = 1, Name = William, Email = [email protected], ContactNo = 999999999 Emplyee ID = 2, Name = Miley, Email = [email protected], ContactNo = 999999999 Emplyee ID = 3, Name = Benjamin, Email = [email protected], ContactNo = Press any key to continue.
LINQ - 对象
LINQ to Objects 允许使用任何支持 IEnumerable
LINQ to Objects 简介
LINQ to Objects 查询通常只返回 `IEnumerable
与传统的 foreach 循环相比,LINQ to Objects 还有许多优点,例如可读性更强、过滤功能更强大、能够进行分组、排序功能增强且应用程序代码最少。这种 LINQ 查询也更简洁,并且可以无需修改或只需少量修改即可移植到任何其他数据源。
下面是一个简单的 LINQ to Objects 示例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LINQtoObjects { class Program { static void Main(string[] args) { string[] tools = { "Tablesaw", "Bandsaw", "Planer", "Jointer", "Drill", "Sander" }; var list = from t in tools select t; StringBuilder sb = new StringBuilder(); foreach (string s in list) { sb.Append(s + Environment.NewLine); } Console.WriteLine(sb.ToString(), "Tools"); Console.ReadLine(); } } }
在此示例中,字符串数组(tools)用作使用 LINQ to Objects 查询的对象集合。
Objects query is: var list = from t in tools select t;
当编译并执行上述代码时,将产生以下结果:
Tablesaw Bandsaw Planer Jointer Drill Sander
使用 LINQ to Objects 查询内存集合
C#
using System; using System.Collections.Generic; using System.Linq; namespace LINQtoObjects { class Department { public int DepartmentId { get; set; } public string Name { get; set; } } class LinqToObjects { static void Main(string[] args) { List<Department> departments = new List<Department>(); departments.Add(new Department { DepartmentId = 1, Name = "Account" }); departments.Add(new Department { DepartmentId = 2, Name = "Sales" }); departments.Add(new Department { DepartmentId = 3, Name = "Marketing" }); var departmentList = from d in departments select d; foreach (var dept in departmentList) { Console.WriteLine("Department Id = {0} , Department Name = {1}", dept.DepartmentId, dept.Name); } Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
VB
Imports System.Collections.Generic Imports System.Linq Module Module1 Sub Main(ByVal args As String()) Dim account As New Department With {.Name = "Account", .DepartmentId = 1} Dim sales As New Department With {.Name = "Sales", .DepartmentId = 2} Dim marketing As New Department With {.Name = "Marketing", .DepartmentId = 3} Dim departments As New System.Collections.Generic.List(Of Department)(New Department() {account, sales, marketing}) Dim departmentList = From d In departments For Each dept In departmentList Console.WriteLine("Department Id = {0} , Department Name = {1}", dept.DepartmentId, dept.Name) Next Console.WriteLine(vbLf & "Press any key to continue.") Console.ReadKey() End Sub Class Department Public Property Name As String Public Property DepartmentId As Integer End Class End Module
当编译并执行上述 C# 或 VB 代码时,将产生以下结果:
Department Id = 1, Department Name = Account Department Id = 2, Department Name = Sales Department Id = 3, Department Name = Marketing Press any key to continue.
LINQ - 数据集
数据集提供了一种极其有用的内存中数据表示形式,并用于各种基于数据应用程序。作为 LINQ to ADO.NET 技术之一,LINQ to DataSet 以轻松的方式促进对数据集数据执行查询,并提高生产力。
LINQ To DataSet 简介
LINQ to DataSet 简化了开发人员的查询任务。他们不需要使用特定的查询语言编写查询,而是可以使用编程语言编写相同的查询。LINQ to DataSet 也可用于查询来自多个数据源的整合数据。这也不需要任何 LINQ 提供程序,就像 LINQ to SQL 和 LINQ to XML 用于访问内存集合中的数据一样。
下面是一个简单的 LINQ to DataSet 查询示例,其中首先获取数据源,然后用两个数据表填充数据集。在两个表之间建立关系,并使用连接子句针对两个表创建 LINQ 查询。最后,使用 foreach 循环显示所需的结果。
C#
using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LINQtoDataset { class Program { static void Main(string[] args) { string connectString = System.Configuration.ConfigurationManager.ConnectionStrings["LinqToSQLDBConnectionString"].ToString(); string sqlSelect = "SELECT * FROM Department;" + "SELECT * FROM Employee;"; // Create the data adapter to retrieve data from the database SqlDataAdapter da = new SqlDataAdapter(sqlSelect, connectString); // Create table mappings da.TableMappings.Add("Table", "Department"); da.TableMappings.Add("Table1", "Employee"); // Create and fill the DataSet DataSet ds = new DataSet(); da.Fill(ds); DataRelation dr = ds.Relations.Add("FK_Employee_Department", ds.Tables["Department"].Columns["DepartmentId"], ds.Tables["Employee"].Columns["DepartmentId"]); DataTable department = ds.Tables["Department"]; DataTable employee = ds.Tables["Employee"]; var query = from d in department.AsEnumerable() join e in employee.AsEnumerable() on d.Field<int>("DepartmentId") equals e.Field<int>("DepartmentId") select new { EmployeeId = e.Field<int>("EmployeeId"), Name = e.Field<string>("Name"), DepartmentId = d.Field<int>("DepartmentId"), DepartmentName = d.Field<string>("Name") }; foreach (var q in query) { Console.WriteLine("Employee Id = {0} , Name = {1} , Department Name = {2}", q.EmployeeId, q.Name, q.DepartmentName); } Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
VB
Imports System.Data.SqlClient Imports System.Linq Module LinqToDataSet Sub Main() Dim connectString As String = System.Configuration.ConfigurationManager.ConnectionStrings("LinqToSQLDBConnectionString").ToString() Dim sqlSelect As String = "SELECT * FROM Department;" + "SELECT * FROM Employee;" Dim sqlCnn As SqlConnection = New SqlConnection(connectString) sqlCnn.Open() Dim da As New SqlDataAdapter da.SelectCommand = New SqlCommand(sqlSelect, sqlCnn) da.TableMappings.Add("Table", "Department") da.TableMappings.Add("Table1", "Employee") Dim ds As New DataSet() da.Fill(ds) Dim dr As DataRelation = ds.Relations.Add("FK_Employee_Department", ds.Tables("Department").Columns("DepartmentId"), ds.Tables("Employee").Columns("DepartmentId")) Dim department As DataTable = ds.Tables("Department") Dim employee As DataTable = ds.Tables("Employee") Dim query = From d In department.AsEnumerable() Join e In employee.AsEnumerable() On d.Field(Of Integer)("DepartmentId") Equals e.Field(Of Integer)("DepartmentId") Select New Person With { _ .EmployeeId = e.Field(Of Integer)("EmployeeId"), .EmployeeName = e.Field(Of String)("Name"), .DepartmentId = d.Field(Of Integer)("DepartmentId"), .DepartmentName = d.Field(Of String)("Name") } For Each e In query Console.WriteLine("Employee Id = {0} , Name = {1} , Department Name = {2}", e.EmployeeId, e.EmployeeName, e.DepartmentName) Next Console.WriteLine(vbLf & "Press any key to continue.") Console.ReadKey() End Sub Class Person Public Property EmployeeId As Integer Public Property EmployeeName As String Public Property DepartmentId As Integer Public Property DepartmentName As String End Class End Module
当编译并执行上述 C# 或 VB 代码时,将产生以下结果:
Employee Id = 1, Name = William, Department Name = Account Employee Id = 2, Name = Benjamin, Department Name = Account Employee Id = 3, Name = Miley, Department Name = Sales Press any key to continue.
使用 LinQ to DataSet 查询数据集
在开始使用 LINQ to DataSet 查询数据集之前,必须将数据加载到数据集,这可以通过使用 DataAdapter 类或 LINQ to SQL 来完成。使用 LINQ to DataSet 编写查询的方式与使用 LINQ 以及其他支持 LINQ 的数据源编写查询的方式非常相似。
单表查询
在下面的单表查询中,从 SalesOrderHeaderTtable 收集所有在线订单,然后显示订单 ID、订单日期以及订单号作为输出。
C#
using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LinqToDataset { class SingleTable { static void Main(string[] args) { string connectString = System.Configuration.ConfigurationManager.ConnectionStrings["LinqToSQLDBConnectionString"].ToString(); string sqlSelect = "SELECT * FROM Department;"; // Create the data adapter to retrieve data from the database SqlDataAdapter da = new SqlDataAdapter(sqlSelect, connectString); // Create table mappings da.TableMappings.Add("Table", "Department"); // Create and fill the DataSet DataSet ds = new DataSet(); da.Fill(ds); DataTable department = ds.Tables["Department"]; var query = from d in department.AsEnumerable() select new { DepartmentId = d.Field<int>("DepartmentId"), DepartmentName = d.Field<string>("Name") }; foreach (var q in query) { Console.WriteLine("Department Id = {0} , Name = {1}", q.DepartmentId, q.DepartmentName); } Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
VB
Imports System.Data.SqlClient Imports System.Linq Module LinqToDataSet Sub Main() Dim connectString As String = System.Configuration.ConfigurationManager.ConnectionStrings("LinqToSQLDBConnectionString").ToString() Dim sqlSelect As String = "SELECT * FROM Department;" Dim sqlCnn As SqlConnection = New SqlConnection(connectString) sqlCnn.Open() Dim da As New SqlDataAdapter da.SelectCommand = New SqlCommand(sqlSelect, sqlCnn) da.TableMappings.Add("Table", "Department") Dim ds As New DataSet() da.Fill(ds) Dim department As DataTable = ds.Tables("Department") Dim query = From d In department.AsEnumerable() Select New DepartmentDetail With { .DepartmentId = d.Field(Of Integer)("DepartmentId"), .DepartmentName = d.Field(Of String)("Name") } For Each e In query Console.WriteLine("Department Id = {0} , Name = {1}", e.DepartmentId, e.DepartmentName) Next Console.WriteLine(vbLf & "Press any key to continue.") Console.ReadKey() End Sub Public Class DepartmentDetail Public Property DepartmentId As Integer Public Property DepartmentName As String End Class End Module
当编译并执行上述 C# 或 VB 代码时,将产生以下结果:
Department Id = 1, Name = Account Department Id = 2, Name = Sales Department Id = 3, Name = Pre-Sales Department Id = 4, Name = Marketing Press any key to continue.
LINQ - XML
LINQ to XML 提供对所有 LINQ 功能(如标准查询运算符、编程接口等)的轻松访问。LINQ to XML 集成在 .NET 框架中,还充分利用了 .NET 框架的功能,例如调试、编译时检查、强类型等。
LINQ to XML 简介
使用 LINQ to XML 时,可以轻松地将 XML 文档加载到内存中,更轻松地进行查询和文档修改。还可以将内存中存在的 XML 文档保存到磁盘并对其进行序列化。它使开发人员无需学习相对复杂的 XML 查询语言。
LINQ to XML 的强大功能体现在 System.Xml.Linq 命名空间中。它包含所有 19 个必要的类来处理 XML。这些类如下所示。
- XAttribute
- XCData
- XComment
- XContainer
- XDeclaration
- XDocument
- XDocumentType
- XElement
- XName
- XNamespace
- XNode
- XNodeDocumentOrderComparer
- XNodeEqualityComparer
- XObject
- XObjectChange
- XObjectChangeEventArgs
- XObjectEventHandler
- XProcessingInstruction
- XText
使用 LINQ 读取 XML 文件
C#
using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; namespace LINQtoXML { class ExampleOfXML { static void Main(string[] args) { string myXML = @"<Departments> <Department>Account</Department> <Department>Sales</Department> <Department>Pre-Sales</Department> <Department>Marketing</Department> </Departments>"; XDocument xdoc = new XDocument(); xdoc = XDocument.Parse(myXML); var result = xdoc.Element("Departments").Descendants(); foreach (XElement item in result) { Console.WriteLine("Department Name - " + item.Value); } Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
VB
Imports System.Collections.Generic Imports System.Linq Imports System.Xml.Linq Module Module1 Sub Main(ByVal args As String()) Dim myXML As String = "<Departments>" & vbCr & vbLf & "<Department>Account</Department>" & vbCr & vbLf & "<Department>Sales</Department>" & vbCr & vbLf & "<Department>Pre-Sales</Department>" & vbCr & vbLf & "<Department>Marketing</Department>" & vbCr & vbLf & "</Departments>" Dim xdoc As New XDocument() xdoc = XDocument.Parse(myXML) Dim result = xdoc.Element("Departments").Descendants() For Each item As XElement In result Console.WriteLine("Department Name - " + item.Value) Next Console.WriteLine(vbLf & "Press any key to continue.") Console.ReadKey() End Sub End Module
当编译并执行上述 C# 或 VB 代码时,将产生以下结果:
Department Name - Account Department Name - Sales Department Name - Pre-Sales Department Name - Marketing Press any key to continue.
添加新节点
C#
using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; namespace LINQtoXML { class ExampleOfXML { static void Main(string[] args) { string myXML = @"<Departments> <Department>Account</Department> <Department>Sales</Department> <Department>Pre-Sales</Department> <Department>Marketing</Department> </Departments>"; XDocument xdoc = new XDocument(); xdoc = XDocument.Parse(myXML); //Add new Element xdoc.Element("Departments").Add(new XElement("Department", "Finance")); //Add new Element at First xdoc.Element("Departments").AddFirst(new XElement("Department", "Support")); var result = xdoc.Element("Departments").Descendants(); foreach (XElement item in result) { Console.WriteLine("Department Name - " + item.Value); } Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
VB
Imports System.Collections.Generic Imports System.Linq Imports System.Xml.Linq Module Module1 Sub Main(ByVal args As String()) Dim myXML As String = "<Departments>" & vbCr & vbLf & "<Department>Account</Department>" & vbCr & vbLf & "<Department>Sales</Department>" & vbCr & vbLf & "<Department>Pre-Sales</Department>" & vbCr & vbLf & "<Department>Marketing</Department>" & vbCr & vbLf & "</Departments>" Dim xdoc As New XDocument() xdoc = XDocument.Parse(myXML) xdoc.Element("Departments").Add(New XElement("Department", "Finance")) xdoc.Element("Departments").AddFirst(New XElement("Department", "Support")) Dim result = xdoc.Element("Departments").Descendants() For Each item As XElement In result Console.WriteLine("Department Name - " + item.Value) Next Console.WriteLine(vbLf & "Press any key to continue.") Console.ReadKey() End Sub End Module
当编译并执行上述 C# 或 VB 代码时,将产生以下结果:
Department Name - Support Department Name - Account Department Name - Sales Department Name - Pre-Sales Department Name - Marketing Department Name - Finance Press any key to continue.
删除特定节点
C#
using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; namespace LINQtoXML { class ExampleOfXML { static void Main(string[] args) { string myXML = @"<Departments> <Department>Support</Department> <Department>Account</Department> <Department>Sales</Department> <Department>Pre-Sales</Department> <Department>Marketing</Department> <Department>Finance</Department> </Departments>"; XDocument xdoc = new XDocument(); xdoc = XDocument.Parse(myXML); //Remove Sales Department xdoc.Descendants().Where(s =>s.Value == "Sales").Remove(); var result = xdoc.Element("Departments").Descendants(); foreach (XElement item in result) { Console.WriteLine("Department Name - " + item.Value); } Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
VB
Imports System.Collections.Generic Imports System.Linq Imports System.Xml.Linq Module Module1 Sub Main(args As String()) Dim myXML As String = "<Departments>" & vbCr & vbLf & "<Department>Support</Department>" & vbCr & vbLf & "<Department>Account</Department>" & vbCr & vbLf & "<Department>Sales</Department>" & vbCr & vbLf & "<Department>Pre-Sales</Department>" & vbCr & vbLf & "<Department>Marketing</Department>" & vbCr & vbLf & "<Department>Finance</Department>" & vbCr & vbLf & "</Departments>" Dim xdoc As New XDocument() xdoc = XDocument.Parse(myXML) xdoc.Descendants().Where(Function(s) s.Value = "Sales").Remove() Dim result = xdoc.Element("Departments").Descendants() For Each item As XElement In result Console.WriteLine("Department Name - " + item.Value) Next Console.WriteLine(vbLf & "Press any key to continue.") Console.ReadKey() End Sub End Module
当编译并执行上述 C# 或 VB 代码时,将产生以下结果:
Department Name - Support Department Name - Account Department Name - Pre-Sales Department Name - Marketing Department Name - Finance Press any key to continue.
LINQ - 实体
LINQ to Entities 作为 ADO.NET Entity Framework 的一部分,比 LINQ to SQL 更灵活,但由于其复杂性和缺乏关键功能而并不流行。但是,它没有 LINQ to SQL 的局限性,后者只允许在 SQL Server 数据库中查询数据,而 LINQ to Entities 则可以方便地在大量数据提供程序(如 Oracle、MySQL 等)中查询数据。
此外,它得到了 ASP.Net 的主要支持,用户可以使用数据源控件通过 LINQ to Entities 执行查询,并无需额外编码即可绑定结果。
由于这些优势,LINQ to Entities 如今已成为在数据库中使用 LINQ 的标准机制。使用 LINQ to Entities 还可以轻松更改查询数据的详细信息并提交批量更新。LINQ to Entities 最引人注目的事实是它具有与 SQL 相同的语法,甚至具有相同的标准查询运算符组,如 Join、Select、OrderBy 等。
LINQ to Entities 查询创建和执行过程
从 **ObjectContext**(实体连接)构建 **ObjectQuery** 实例
使用新构建的实例使用 C# 或 Visual Basic (VB) 编写查询
将 LINQ 的标准查询运算符以及 LINQ 表达式转换为命令树
执行查询,并将遇到的任何异常直接传递给客户端
将所有查询结果返回给客户端
**ObjectContext** 是这里的主要类,它能够与 **Entity Data Model** 交互,或者换句话说,它充当连接 LINQ 和数据库的桥梁。命令树是此处与 Entity Framework 兼容的查询表示。
另一方面,Entity Framework 实际上是 **对象关系映射器**,开发人员通常将其缩写为 ORM,它根据数据库表生成业务对象和实体,并促进创建、更新、删除和读取等各种基本操作。下图显示了实体框架及其组件。
使用 LINQ 和实体模型进行 ADD、UPDATE 和 DELETE 的示例
首先按照以下步骤添加实体模型。
**步骤 1** - 右键单击项目并单击“添加新项”将打开如下所示的窗口。选择 ADO.NET 实体数据模型,指定名称,然后单击“添加”。
**步骤 2** - 选择 **从数据库生成**。
**步骤 3** - 从下拉菜单中选择数据库连接。
**步骤 4** - 选择所有表。
现在编写以下代码。
using DataAccess; using System; using System.Linq; namespace LINQTOSQLConsoleApp { public class LinqToEntityModel { static void Main(string[] args) { using (LinqToSQLDBEntities context = new LinqToSQLDBEntities()) { //Get the List of Departments from Database var departmentList = from d in context.Departments select d; foreach (var dept in departmentList) { Console.WriteLine("Department Id = {0} , Department Name = {1}", dept.DepartmentId, dept.Name); } //Add new Department DataAccess.Department department = new DataAccess.Department(); department.Name = "Support"; context.Departments.Add(department); context.SaveChanges(); Console.WriteLine("Department Name = Support is inserted in Database"); //Update existing Department DataAccess.Department updateDepartment = context.Departments.FirstOrDefault(d ⇒d.DepartmentId == 1); updateDepartment.Name = "Account updated"; context.SaveChanges(); Console.WriteLine("Department Name = Account is updated in Database"); //Delete existing Department DataAccess.Department deleteDepartment = context.Departments.FirstOrDefault(d ⇒d.DepartmentId == 3); context.Departments.Remove(deleteDepartment); context.SaveChanges(); Console.WriteLine("Department Name = Pre-Sales is deleted in Database"); //Get the Updated List of Departments from Database departmentList = from d in context.Departments select d; foreach (var dept in departmentList) { Console.WriteLine("Department Id = {0} , Department Name = {1}", dept.DepartmentId, dept.Name); } } Console.WriteLine("\nPress any key to continue."); Console.ReadKey(); } } }
当编译并执行上述代码时,将产生以下结果:
LINQ - Lambda 表达式
术语“Lambda 表达式”来源于“lambda 演算”,后者是一种用于定义函数的数学符号。作为 LINQ 方程的可执行部分,Lambda 表达式以运行时的方式转换逻辑,以便可以方便地将其传递给数据源。但是,Lambda 表达式不仅限于在 LINQ 中使用。
这些表达式由以下语法表示:
(Input parameters) ⇒ Expression or statement block
这是一个 Lambda 表达式的示例:
y ⇒ y * y
上述表达式指定了一个名为 y 的参数,并且 y 的值是平方。但是,无法以这种形式执行 Lambda 表达式。下面显示了 C# 中 Lambda 表达式的示例。
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace lambdaexample { class Program { delegate int del(int i); static void Main(string[] args) { del myDelegate = y ⇒ y * y; int j = myDelegate(5); Console.WriteLine(j); Console.ReadLine(); } } }
VB
Module Module1 Private Delegate Function del(ByVal i As Integer) As Integer Sub Main(ByVal args As String()) Dim myDelegate As del = Function(y) y * y Dim j As Integer = myDelegate(5) Console.WriteLine(j) Console.ReadLine() End Sub End Module
当编译并执行上述 C# 或 VB 代码时,将产生以下结果:
25
表达式 Lambda
由于上述 Lambda 表达式语法的表达式位于右侧,因此它们也被称为表达式 Lambda。
异步 Lambda
通过使用 async 关键字结合异步处理创建的 Lambda 表达式称为异步 Lambda。下面是一个异步 Lambda 的示例。
Func<Task<string>> getWordAsync = async()⇒ “hello”;
标准查询运算符中的 Lambda
查询运算符中的 Lambda 表达式由同一个按需计算,并持续处理输入序列中的每个元素,而不是整个序列。Lambda 表达式允许开发人员将自己的逻辑输入标准查询运算符。在下面的示例中,开发人员使用了“Where”运算符,通过使用 Lambda 表达式从给定的列表中取回奇数值。
C#
//Get the average of the odd Fibonacci numbers in the series... using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace lambdaexample { class Program { static void Main(string[] args) { int[] fibNum = { 1, 1, 2, 3, 5, 8, 13, 21, 34 }; double averageValue = fibNum.Where(num ⇒ num % 2 == 1).Average(); Console.WriteLine(averageValue); Console.ReadLine(); } } }
VB
Module Module1 Sub Main() Dim fibNum As Integer() = {1, 1, 2, 3, 5, 8, 13, 21, 34} Dim averageValue As Double = fibNum.Where(Function(num) num Mod 2 = 1).Average() Console.WriteLine(averageValue) Console.ReadLine() End Sub End Module
当编译并执行上述代码时,将产生以下结果:
7.33333333333333
Lambda 中的类型推断
在 C# 中,类型推断可以方便地用于各种情况下,而且无需显式指定类型。但是,对于 Lambda 表达式,类型推断仅在已指定每个类型时才有效,因为编译器必须得到满足。让我们考虑以下示例。
delegate int Transformer (int i);
编译器在这里使用类型推断来推断 x 是一个整数,这是通过检查 Transformer 的参数类型来完成的。
Lambda 表达式中的变量作用域
在 Lambda 表达式中使用变量作用域时有一些规则,例如在 Lambda 表达式中初始化的变量不能在外部方法中可见。还有一个规则是,除非引用它的委托有资格进行垃圾回收,否则捕获的变量不会被垃圾回收。此外,还有一条规则禁止 Lambda 表达式中的 return 语句导致封闭方法返回。
这是一个演示 Lambda 表达式中变量作用域的示例。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace lambdaexample { class Program { delegate bool D(); delegate bool D2(int i); class Test { D del; D2 del2; public void TestMethod(int input) { int j = 0; // Initialize the delegates with lambda expressions. // Note access to 2 outer variables. // del will be invoked within this method. del = () ⇒ { j = 10; return j > input; }; // del2 will be invoked after TestMethod goes out of scope. del2 = (x) ⇒ { return x == j; }; // Demonstrate value of j: // The delegate has not been invoked yet. Console.WriteLine("j = {0}", j); // Invoke the delegate. bool boolResult = del(); Console.WriteLine("j = {0}. b = {1}", j, boolResult); } static void Main() { Test test = new Test(); test.TestMethod(5); // Prove that del2 still has a copy of // local variable j from TestMethod. bool result = test.del2(10); Console.WriteLine(result); Console.ReadKey(); } } } }
当编译并执行上述代码时,将产生以下结果:
j = 0 j = 10. b = True True
表达式树
Lambda 表达式广泛用于 **表达式树** 的构建。表达式树以类似树的数据结构提供代码,其中每个节点本身就是一个表达式,例如方法调用,或者可以是二元运算,例如 x 还有 **语句 Lambda**,它包含两到三个语句,但不用于构建表达式树。必须在语句 Lambda 中编写 return 语句。 语句 Lambda 的语法 当编译并执行上述代码时,将产生以下结果: Lambda 用作基于方法的 LINQ 查询中的参数,并且不允许像匿名方法一样位于运算符(如 **is** 或 **as**)的左侧。虽然 Lambda 表达式与匿名方法非常相似,但它们并不局限于仅用作委托。 Lambda 表达式可以返回值,并且可以有参数。 可以使用多种方式在 Lambda 表达式中定义参数。 如果 Lambda 表达式中只有一个语句,则不需要花括号;如果有多个语句,则需要编写花括号和返回值。 使用 Lambda 表达式,可以通过称为闭包的功能访问 Lambda 表达式块外部存在的变量。应谨慎使用闭包,以免出现任何问题。 无法在任何 Lambda 表达式内执行任何不安全的代码。 Lambda 表达式不能用于运算符的左侧。 作为一组 .NET 框架扩展,LINQ 是 ASP.NET 开发人员首选的数据访问机制。ASP.NET 3.5 内置了一个 LINQDataSource 控件,可以轻松地在 ASP.NET 中使用 LINQ。ASP.NET 使用上述控件作为数据源。现实项目大多包含网站或 Windows 应用程序,因此为了更好地理解 ASP.NET 中 LINQ 的概念,让我们从创建一个使用 LINQ 功能的 ASP.NET 网站开始。 为此,必须在您的系统上安装 Visual Studio 和 .NET 框架。打开 Visual Studio 后,转到文件 → 新建 → 网站。将打开一个弹出窗口,如下所示。 现在,在左侧的模板下,将有两个语言选项可用于创建网站。选择 **Visual C#** 并选择 **ASP.NET 空网站**。 选择要在系统上保存新网站的文件夹。然后按 **确定**,很快 **解决方案资源管理器** 将出现在您的屏幕上,其中包含所有 Web 文件。右键单击解决方案资源管理器中的 Default.aspx,然后选择在浏览器中查看,以在浏览器中查看默认的 ASP.NET 网站。很快,您的新 ASP.NET 网站将在 Web 浏览器中打开,如下面的屏幕截图所示。 .aspx 事实上是 ASP.NET 网站中使用的主要文件扩展名。Visual Studio 默认情况下会为基本的网站创建所有必要的页面,例如 **主页** 和 **关于我们** 页面,您可以在其中方便地放置您的内容。网站的代码在此处自动生成,也可以查看。 借助 LINQDataSource 控件,可以在 ASP.NET 网站的页面中 **更新、插入** 和 **删除** 数据。完全无需指定 SQL 命令,因为 LINQDataSource 控件会为这类操作采用动态生成的命令。 该控件使用户可以通过标记文本中的属性设置,方便地在 ASP.NET 网页中使用 LINQ。LINQDataSource 与 **SqlDataSource** 和 **ObjectDataSource** 等控件非常相似,因为它可以用于将页面上存在的其他 ASP.NET 控件绑定到数据源。因此,我们必须拥有一个 **数据库** 来解释 LINQDataSource 控件调用的各种函数。 在开始解释在 ASP.NET 网页表单中使用该控件之前,必须打开 Microsoft Visual Studio 工具箱并将 LINQDataSource 控件拖放到 ASP.NET 网站的 .aspx 页面上,如下图所示。 下一步是配置 LINQDataSource,选择员工记录的所有列。 现在,向 .aspx 页面添加 GridView 控件并对其进行配置,如下图所示。GridView 控件功能强大,并提供处理数据的灵活性。配置控件后,它将很快出现在浏览器中。 现在可以在屏幕上查看 .aspx 页面的代码: 这里应该注意的是,必须将 ContextTypeName 属性设置为表示数据库的类的属性。例如,这里将其设置为 LINQWebApp1.AdventureWorksDataContext,因为此操作将建立 LINQDataSource 和数据库之间的必要连接。 严格完成上述所有步骤后,从 **LINQDataSource 控件** 中选择 **LINQDataSource 任务**,并从其中选择所有三个复选框以启用插入、启用更新和启用删除,如下图所示。 很快,声明性标记将显示在您的屏幕上,如下所示。 现在,由于有多行和多列,最好在 .aspx 表单上添加另一个名为“详细信息视图”或“主控件”的控件,该控件位于 GridView 控件下方,以仅显示所选网格行的详细信息。从“详细信息视图”控件中选择“详细信息视图任务”,然后选择如下所示的复选框。 现在,只需保存更改并按 Ctrl + F5 即可在浏览器中查看页面,现在可以在详细信息视图控件上删除、更新和插入任何记录。语句 Lambda
(params)⇒ {statements}
语句 Lambda 的示例
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace lambdaexample {
class Program {
static void Main(string[] args) {
int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };
foreach (int i in source.Where(x ⇒
{
if (x <= 3)
return true;
else if (x >= 7)
return true;
return false;
}
))
Console.WriteLine(i);
Console.ReadLine();
}
}
}
3
8
1
7
9
2
8
使用 Lambda 表达式时需要注意的事项
LINQ - ASP.Net
LINQDataSource 控件
<!DOCTYPE html>
<html>
<head runat = "server">
<title></title>
</head>
<body>
<form id = "form1" runat = "server">
<div>
<asp:GridView ID = "GridView1" runat = "server" AutoGenerateColumns = "False"
DataKeyNames = "ContactID" DataSourceID = "LINQDataSource1">
<Columns>
<asp:BoundField DataField = "ContactID" HeaderText = "ContactID"
InsertVisible = "False" ReadOnly="True" SortExpression = "ContactID" />
<asp:CheckBoxField DataField = "NameStyle" HeaderText = "NameStyle"
SortExpression = "NameStyle" />
<asp:BoundField DataField = "Title" HeaderText = "Title" SortExpression = "Title" />
<asp:BoundField DataField = "FirstName" HeaderText = "FirstName"
SortExpression="FirstName" />
<asp:BoundField DataField = "MiddleName" HeaderText = "MiddleName"
SortExpression = "MiddleName" />
<asp:BoundField DataField = "LastName" HeaderText = "LastName"
SortExpression = "LastName" />
<asp:BoundField DataField = "Suffix" HeaderText = "Suffix"
SortExpression = "Suffix" />
<asp:BoundField DataField = "EmailAddress" HeaderText = "EmailAddress"
SortExpression = "EmailAddress" />
</Columns>
</asp:GridView>
<br />
</div>
<asp:LINQDataSource ID = "LINQDataSource1" runat = "server"
ContextTypeName = "LINQWebApp1.AdventureWorksDataContext" EntityTypeName = ""
TableName = "Contacts">
</asp:LINQDataSource>
</form>
</body>
</html>
使用 LINQ 在 ASP.NET 页面中插入、更新和删除数据
<asp:LINQDataSource
ContextTypeName = "LINQWebApp1.AdventureWorksDataContext"
TableName = "Contacts"
EnableUpdate = "true"
EnableInsert = "true"
EnableDelete = "true"
ID = "LINQDataSource1"
runat = "server">
</asp:LINQDataSource>