Linq 简明教程

LINQ - Quick Guide

LINQ - Overview

由于缺少明确的路径,并需要精通 SQL、Web 服务、XQuery 等多项技术,世界各地的开发人员在查询数据时总会遇到问题。

LINQ(语言集成查询)由 Anders Hejlsberg 设计,在 Visual Studio 2008 中引入,允许编写查询,即使不知道 SQL、XML 等查询语言。可为不同数据类型编写 LINQ 查询。

Example of a LINQ query

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

Syntax of LINQ

LINQ 的语法有两种。它们如下所示。

Lamda (Method) Syntax

var longWords = words.Where( w ⇒ w.length > 10);
Dim longWords = words.Where(Function(w) w.length > 10)

Query (Comprehension) Syntax

var longwords = from w in words where w.length > 10;
Dim longwords = from w in words where w.length > 10

Types of LINQ

LINQ 的类型概述如下。

  1. LINQ to Objects

  2. LINQ to XML(XLINQ)

  3. LINQ to DataSet

  4. LINQ to SQL (DLINQ)

  5. LINQ to Entities

除了上述类型之外,还有一个名为 PLINQ 的 LINQ 类型,它是 Microsoft 提供的并行 LINQ。

LINQ Architecture in .NET

LINQ 具有一个 3 层架构,其中最上层由语言扩展组成,最底层由通常实现 IEnumerable 或 IQueryable 通用接口的对象(数据源)组成。该架构如下所示。

linq architecture

Query Expressions

查询表达式只不过是一个 LINQ 查询,它以类似于 SQL 的形式表示,带有 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

Extension Methods

使用 .NET 3.5 引入,仅在静态类中声明扩展方法,并允许将自定义方法包含到对象中,以执行一些精确的查询操作,而无需成为该类的实际成员。这些方法还可以重载。

简而言之,扩展方法用于将查询表达式转换为传统方法调用(面向对象)。

Difference between LINQ and Stored Procedure

LINQ 和存储过程之间有很多差异。这些差异如下所述。

  1. 存储过程要比 LINQ 查询快得多,因为它们遵循预期的执行计划。

  2. 执行 LINQ 查询比存储过程更容易避免运行时错误,因为前者具有 Visual Studio 的 Intellisense 支持以及编译时的完全类型检查。

  3. LINQ 允许通过使用存储过程不存在的 .NET 调试器进行调试。

  4. LINQ 支持多个数据库,而存储过程则不同,存储过程需要为不同类型的数据库重写代码。

  5. 基于 LINQ 的解决方案的部署比部署一组存储过程更容易、更简单。

Need For 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,相同的 data 查询可以用可读的彩色彩色形式编写,如下所示,而且时间非常短。

Northwind db = new Northwind(@"C:\Data\Northwnd.mdf");
var query = from c in db.Customers select c;

Advantages of LINQ

LINQ 提供了许多优势,其中首要优势是其强大的表达能力,使开发人员能够以声明方式表达。以下列出了 LINQ 的其他一些优势。

  1. LINQ 提供语法高亮显示,这有助于在设计时发现错误。

  2. LINQ 提供 IntelliSense,这意味着可以轻松编写更准确的查询。

  3. 在 LINQ 中编写代码的速度非常快,因此开发时间也大大缩短。

  4. 由于 LINQ 集成在 C# 语言中,所以易于调试。

  5. 由于 LINQ 层次化的特性,所以轻松查看两个表之间的关系,这可以在更短的时间内通过连接多个表组成查询。

  6. LINQ 允许在查询多个不同数据源时使用单一的 LINQ 语法,这主要是因为它的统一基础。

  7. LINQ 是可扩展的,这意味着可以使用 LINQ 知识查询新的数据源类型。

  8. LINQ 提供连接多个数据源于一个查询以及将复杂的问题分解为一组易于调试的简短查询的功能。

  9. LINQ 提供了轻松的转换功能,例如将一种数据类型转换为另一种数据类型,例将 SQL 数据转换为 XML 数据。

LINQ - Environment Setup

在开始使用 LINQ 程序前,最好先了解 LINQ 环境的设置细节。LINQ 需要一个 .NET 框架,这是一种革命性的平台,可拥有各种应用程序。LINQ 查询既可以用 C# 也可用 Visual Basic 方便地编写。

微软通过 Visual Studio 为这两种语言 (即 C# 和 Visual Basic) 提供工具。我们的示例全部在 Visual Studio 2010 中编译和编写。但是,Visual Basic 2013 版也可以使用。它是最新版本,并且与 Visual Studio 2012 有许多相似之处。

Getting Visual Studio 2010 Installed on Windows 7

Visual Studio 可以从安装介质(如 DVD)中安装。成功在系统中安装 Visual Basic 2010 需要管理员凭据。在安装之前,必须断开系统中所有可移动 USB,否则安装可能会失败。以下列出了一些安装中必备的硬件要求。

Hardware Requirements

  1. 1.6 GHz or more

  2. 1 GB RAM

  3. 3 GB(Available hard-disk space)

  4. 5400 RPM hard-disk drive

  5. DirectX 9 兼容视频卡

  6. DVD-ROM drive

Installation Steps

Step 1 − 首先在插入 Visual Studio 2010 组件包 DVD 后,单击屏幕上弹出框中出现的 Install or run program from your media

Step 2 − 现在屏幕上会出现 Visual Studio 的设置。选择 Install Microsoft Visual Studio 2010

linq environment 1

Step 3 − 单击后,进程将启动,并且屏幕上会出现设置窗口。在完成安装组件的加载(这需要一些时间)后,单击 Next 按钮以移至下一步。

linq environment 2

Step 4 − 这是安装的最后一步,并且将出现一个开始页面,在其中只需选择“我已阅读并接受许可证条款”,然后单击 Next 按钮。

linq environment 3

Step 5 − 现在从屏幕上出现的选项页面中选择要安装的功能。您可以选择 FullCustom 选项。如果您拥有的磁盘空间少于磁盘空间要求中显示所需的磁盘空间,请使用“自定义”。

linq environment 4

Step 6 − 选择“自定义”选项,以下窗口将出现。选择要安装的功能,然后单击 Update ,否则请转到步骤 7。但是,建议不要使用自定义选项,因为在将来,您可能需要您选择不安装的功能。

linq environment 5

Update − 不久后将显示一个弹出窗口,并且安装将开始,这可能需要很长时间。请记住,这是为了安装所有组件。

linq environment 6

Step 8 − 最后,您将可以在窗口中看到一条消息,提示安装已成功完成。单击 Finish

linq environment 7

Writing C

  1. 启动 Visual Studio 2010 Ultimate 版,然后从菜单中选择“文件”,然后选择“新建项目”。

  2. 屏幕上将出现一个新项目对话框。

  3. 现在将 Visual C# 选择为已安装模板下的一个类别,然后选择控制台应用程序模板,如下图所示。

linq Csharp program 1
  1. 在底部的名称框中为项目指定一个名称,然后按“确定”。

  2. 此新项目将显示在屏幕上的一个新对话框右侧的解决方案资源管理器中。

linq Csharp program 2
  1. 现在从解决方案资源管理器中选择 Program.cs,则可以在编辑器窗口中查看以“using System”开头的代码。

  2. 在这里,您可以开始编写以下 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();
      }
   }
}
  1. 按 F5 键并运行您的项目。强烈建议在运行项目之前通过选择 FileSave All 保存项目。

Writing VB Program using LINQ in Visual Studio 2010

  1. 启动 Visual Studio 2010 Ultimate 版,然后从菜单中选择“文件”,然后选择“新建项目”。

  2. 屏幕上将出现一个新项目对话框。

  3. 现在在已安装的模板下选择 Visual Basic 作为类别,然后选择控制台应用程序模板。

  4. 在底部的名称框中为项目指定一个名称,然后按“确定”。

  5. 您将获得一个带 Module1.vb 的屏幕。开始在此处使用 LINQ 编写您的VB 代码。

Module Module1

   Sub Main()
      Console.WriteLine("Hello World")
      Console.ReadLine()
   End Sub

End Module
  1. 按 F5 键并运行您的项目。强烈建议在运行项目之前通过选择 FileSave All 保存项目。

当上面 C# 或 VB 代码 cimpiled 并运行时,它会产生以下结果 -

Hello World

LINQ - Query Operators

形成查询模式的一组扩展方法被称为 LINQ 标准查询运算符。作为 LINQ 查询表达式的构建块,这些运算符提供了一系列查询功能,如筛选、排序、投影、聚合等。

LINQ 标准查询运算符可以根据其功能归类为以下类。

  1. Filtering Operators

  2. Join Operators

  3. Projection Operations

  4. Sorting Operators

  5. Grouping Operators

  6. Conversions

  7. Concatenation

  8. Aggregation

  9. Quantifier Operations

  10. Partition Operations

  11. Generation Operations

  12. Set Operations

  13. Equality

  14. Element Operators

Filtering Operators

筛选是一种操作,用于限制结果集,以便它只有满足特定条件的选定元素。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

where

根据谓词函数筛选值

where

Where

OfType

根据其作为指定类型的可能性筛选值

Not Applicable

Not Applicable

Join Operators

联接是指以直接方式针对难以相互跟踪关系的数据源的操作。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

Join

联接基于匹配的键连接两个序列

联接 … 在 … 时 … 等于…

从 x 中 …,y 中 … 其中 x.a = y.a

GroupJoin

联接两个序列并分组匹配的元素

join … in … on … equals … into …

Group Join … In … On …

Projection Operations

投影是一种将对象转换成具有特定属性的全新形式的操作。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

Select

运算符基于转换函数投影值

select

Select

SelectMany

运算符投影基于转换函数的值序列,并将它们压扁成单个序列

Use multiple from clauses

Use multiple From clauses

Sorting Operators

排序操作允许基于单个或多个属性对序列的元素进行排序。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

OrderBy

运算符按升序对值进行排序

orderby

Order By

OrderByDescending

运算符按降序对值进行排序

orderby …​ descending

Order By …​ Descending

ThenBy

按升序执行二次排序

orderby …, …

Order By …, …

ThenByDescending

按降序执行二次排序

orderby …, … descending

Order By …, … Descending

Reverse

对集合中的元素顺序进行颠倒

Not Applicable

Not Applicable

Grouping Operators

运算符基于常用共享属性将数据放入到某些组中。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

GroupBy

按组组织项目序列并将其作为 IGrouping<key, element> 类型的 IEnumerable 集合返回

group … by -or- group … by … into …

Group … By … Into …

ToLookup

执行分组操作,其中返回一系列键对

Not Applicable

Not Applicable

Conversions

运算符会更改输入对象的类型,应用于各类应用程序中。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

AsEnumerable

将输入类型返回为 IEnumerable<T>

Not Applicable

Not Applicable

AsQueryable

(泛型)IEnumerable 被转换为(泛型)IQueryable

Not Applicable

Not Applicable

Cast

执行将集合元素强制转换为指定类型

使用显式类型范围变量。例如:from string str in words

From … As …

OfType

根据值的能力而根据其类型对其进行筛选,具体取决于它们是否可以强制转换为特定类型

Not Applicable

Not Applicable

ToArray

强制执行查询并执行从集合到数组的转换

Not Applicable

Not Applicable

ToDictionary

根据键选择器函数将元素设置到 Dictionary<TKey, TValue> 中,并且强制执行 LINQ 查询

Not Applicable

Not Applicable

ToList

通过将集合转换为 List<T> 来强制执行查询

Not Applicable

Not Applicable

ToLookup

强制执行查询,并且根据键选择器函数将元素放入到 Lookup<TKey, TElement> 中

Not Applicable

Not Applicable

Concatenation

执行两个序列的连接,并且除不删除重复项这一事实外,在操作方面与 Union 运算符很相似。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

Concat

连接两个序列,形成一个序列。

Not Applicable

Not Applicable

Aggregation

执行任何类型的所需聚合,并允许在 LINQ 中创建自定义聚合。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

Aggregate

针对集合的值操作来执行自定义聚合操作

Not Applicable

Not Applicable

Average

计算出值集合的平均值

Not Applicable

聚合…到…转换为 Average()

Count

统计满足集合中谓词函数的元素

Not Applicable

聚合…到…转换为 Count()

LonCount

统计满足巨型集合中谓词函数的元素

Not Applicable

聚合…到…转换为 LongCount()

Max

找出集合中的最大值

Not Applicable

聚合…到…转换为 Max()

Min

找出集合中存在的最小值

Not Applicable

聚合…到…转换为 Min()

Sum

找出集合中值的总和

Not Applicable

聚合…到…转换为 Sum()

Quantifier Operations

当序列中某些或所有元素满足特定条件时,这些运算符会返回布尔值,即 True 或 False。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

All

如果序列的所有元素都满足谓词条件,则返回“True”值

Not Applicable

聚合…到…转换为 All(…)

Any

通过搜索序列确定其任何元素是否满足指定条件

Not Applicable

聚合…到…转换为 Any()

Contains

如果发现序列中存在特定元素,则返回“True”值;如果序列不包含该特定元素,则返回“false”值

Not Applicable

Not Applicable

Partition Operators

将输入序列划分为不重新排列序列元素的两个独立部分,然后返回其中之一。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

Skip

在序列中跳过指定数量的元素,并返回剩余元素

Not Applicable

Skip

SkipWhile

与 Skip 相同,唯一不同的是要跳过的元素数量由一个布尔条件指定

Not Applicable

Skip While

Take

从序列中取指定数量的元素,并跳过其余元素

Not Applicable

Take

TakeWhile

与 Take 相同,但不同之处在于要取的元素数量由一个布尔条件指定

Not Applicable

Take While

Generation Operations

新值序列由生成运算符创建。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

DefaultIfEmpty

当应用于空序列时,在序列中生成一个默认元素

Not Applicable

Not Applicable

Empty

返回空值序列,是最简单的生成运算符

Not Applicable

Not Applicable

Range

生成具有整数或数字序列的集合

Not Applicable

Not Applicable

Repeat

生成包含特定长度的重复值序列

Not Applicable

Not Applicable

Set Operations

集合运算有四个运算符,每个运算符根据不同的条件产生结果。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

Distinct

通过过滤重复数据(如果有的话),生成集合中唯一值的列表

Not Applicable

Distinct

Except

比较两个集合的值,并返回一个集合中的值,而另一个集合中不存在

Not Applicable

Not Applicable

Intersect

返回在两个不同集合中发现的值相同的集合

Not Applicable

Not Applicable

Union

将两个不同集合的内容组合成一个列表,并且没有任何重复内容

Not Applicable

Not Applicable

Equality

比较两个句子(可枚举的),并确定它们是否完全匹配。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

SequenceEqual

如果两个序列彼此相同,则结果为布尔值

Not Applicable

Not Applicable

Element Operators

除了 DefaultIfEmpty,所有其他八个标准查询元素运算符都会从一个集合返回一个单一元素。

Operator

Description

C# Query Expression Syntax

VB Query Expression Syntax

ElementAt

返回集合中特定索引内存在的元素

Not Applicable

Not Applicable

ElementAtOrDefault

与 ElementAt 相同,除了在特定索引超出范围时返回默认值

Not Applicable

Not Applicable

First

检索集合中的第一个元素或满足特定条件的第一个元素

Not Applicable

Not Applicable

FirstOrDefault

与 First 相同,除了在没有这样的元素时返回默认值

Not Applicable

Not Applicable

Last

检索集合中存在的最后一个元素或满足特定条件的最后一个元素

Not Applicable

Not Applicable

LastOrDefault

与 Last 相同,除了在没有这样的元素时返回默认值

Not Applicable

Not Applicable

Single

返回集合的单个元素或满足特定条件的单个元素

Not Applicable

Not Applicable

SingleOrDefault

与 Single 相同,除了在没有这样的单个元素时返回默认值

Not Applicable

Not Applicable

DefaultIfEmpty

如果集合或列表为空或 null,则返回默认值

Not Applicable

Not Applicable

LINQ - SQL

LINQ to SQL 为管理对象关系数据提供一个基础结构(运行时)。它是 .NET Framework 3.5 版本的一个组件,能够将对象模型的语言集成查询翻译成 SQL。然后将这些查询发送到数据库以供执行。在从数据库获取结果后,LINQ to SQL 会再次将结果转换为对象。

Introduction of LINQ To SQL

对于大多数的 ASP.NET 开发人员而言,LINQ to SQL(也称为 DLINQ)是语言集成查询中令人振奋的部分,因为它可以通过使用通常的 LINQ 表达式来查询 SQL 服务器数据库。它还允许更新、删除和插入数据,但它所遭受的唯一缺点是它仅限于 SQL 服务器数据库。然而,LINQ to SQL 相较于 ADO.NET 具有许多优势,例如复杂度降低、编码行数减少等等。

以下是显示 LINQ to SQL 执行架构的图表。

linq sql architecture

How to Use LINQ to SQL?

Step 1 - 与数据库服务器建立新的“数据连接”。查看 & Farrar; 服务器资源管理器 & Farrar; 数据连接 & Farrar; 添加连接

linq sql 1

Step 2 - 添加 LINQ To SQL 类文件

linq sql 2

Step 3 - 从数据库中选择表并将其拖放到新的 LINQ to SQL 类文件中。

linq sql 3

Step 4 - 已将表添加到类文件中。

linq sql 4

Querying with LINQ to SQL

使用 LINQ to SQL 执行查询的规则类似于标准 LINQ 查询,即延迟或立即执行查询。有各种组件在使用 LINQ to SQL 执行查询中发挥作用,如下所示。

  1. LINQ to SQL API - 代表应用程序请求查询执行,并将其发送到 LINQ to SQL 提供程序。

  2. LINQ to SQL Provider - 将查询转换为事务 SQL(T-SQL),并将新查询发送到 Ado 提供程序以供执行。

  3. ADO Provider - 在执行查询后,将结果以 DataReader 形式发送到 LINQ to SQL 提供程序,而后者又将其转换为用户对象的形式。

需要注意的是,在执行 LINQ to SQL 查询之前,必须通过 DataContext 类连接到数据源。

Insert, Update and Delete using LINQ To SQL

Add OR Insert

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 = "yourname@companyname.com";
         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 = "yourname@companyname.com"
      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 = yourname@companyname.com, ContactNo =
343434343, Address = Michael - USA

Press any key to continue.

Update

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 = "yourname@companyname.com";
         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 = "yourname@companyname.com"
      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 = yourname@companyname.com, ContactNo =
999999999, Address = Michael George - UK

Press any key to continue.

Delete

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 = abc@gy.co, ContactNo = 999999999
Emplyee ID = 2, Name = Miley, Email = amp@esds.sds, ContactNo = 999999999
Emplyee ID = 3, Name = Benjamin, Email = asdsad@asdsa.dsd, ContactNo =

Press any key to continue.

LINQ - Objects

LINQ to Objects 提供对任何支持 IEnumerable<T> 的 LINQ 查询的使用,用于访问内存中数据集合,无需 LINQ 提供程序 (API),如 LINQ to SQL 或 LINQ to XML。

Introduction of LINQ to Objects

LINQ to Objects 中的查询通常仅返回类型为 IEnumerable<T> 的变量。简而言之,LINQ to Objects 提供了一种新的集合方法,如前所述,以前必须编写长编码(非常复杂的 foreach 循环)才能从集合中检索数据,现在已替换为编写声明性代码,其中明确描述了需要检索的目标数据。

LINQ to Objects 还比传统的 foreach 循环具有更多的优势,例如,可读性更好,过滤功能更强大,分组功能更强大,增强排序功能,同时应用程序编码更少。此类 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();
      }
   }
}

在该示例中,字符串数组(工具)用作使用 LINQ to Objects 查询的对象集合。

Objects query is:
var list = from t in tools select t;

编译并执行上述代码后,将产生以下结果 −

Tablesaw
Bandsaw
Planer
Jointer
Drill
Sander

Querying in Memory Collections Using 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 - Dataset

数据集在内存中提供了非常有用的数据表示形式,并且用于各种基于数据的应用程序。作为 LINQ to ADO.NET 技术之一的 LINQ to Dataset 促进了对数据集数据执行查询的便利,并且提高了工作效率。

Introduction of 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.

Querying Dataset using LinQ to Dataset

在使用 LINQ to Dataset 查询数据集之前,至关重要的是将数据加载到数据集,这是通过使用 DataAdapter 类或通过 LINQ to SQL 来完成的。使用 LINQ to Dataset 制定的查询与使用 LINQ 以及其他启用了 LINQ 的数据源来制定查询非常相似。

Single-Table Query

在以下单表查询中,从 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 框架功能,如调试、编译时检查、强类型等等。

Introduction of LINQ to XML

在使用 LINQ to XML 时,可以轻松地将 XML 文档加载到内存中,并且更容易查询和修改文档。还可以将内存中现有的 XML 文档保存到磁盘并对其进行序列化。它消除了开发人员学习有些复杂的 XML 查询语言的需要。

LINQ to XML 的功能在 System.Xml.Linq 命名空间中。这拥有 19 个与 XML 配合使用必不可少的类。这些类如下。

  1. XAttribute

  2. XCData

  3. XComment

  4. XContainer

  5. XDeclaration

  6. XDocument

  7. XDocumentType

  8. XElement

  9. XName

  10. XNamespace

  11. XNode

  12. XNodeDocumentOrderComparer

  13. XNodeEqualityComparer

  14. XObject

  15. XObjectChange

  16. XObjectChangeEventArgs

  17. XObjectEventHandler

  18. XProcessingInstruction

  19. XText

Read an XML File using LINQ

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.

Add New Node

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.

Deleting Particular Node

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 - Entities

作为 ADO.NET 实体框架的一部分,LINQ to Entities 比 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 相同的语法,甚至拥有相同的标准查询操作符组,如“联接”、“选择”、“按顺序排列”等。

LINQ to Entities Query Creation and Execution Process

  1. 根据 ObjectQuery (Entity 连接)构造 ObjectContext 实例

  2. 使用新构造的实例用 C# 或 Visual Basic (VB) 中的编写查询

  3. 将 LINQ 的标准查询操作符以及 LINQ 表达式转换成命令树

  4. 执行查询,将遇到的任何异常直接传递给客户端

  5. 向客户端返回所有查询结果

ObjectContext 这里的主要类,可与 Entity Data Model 交互;换句话说,它起到了 LINQ 与数据库之间的桥梁作用。命令树这里是为了与 Entity 框架兼容的查询表示形式。

另一方面,Entity Framework 实际上是 Object Relational Mapper ,开发人员通常将其缩写为 ORM,它可以根据数据库表生成业务对象以及实体,并支持各种基本操作,如创建、更新、删除和读取。下图显示了 Entity 框架及其组件。

linq entities

Example of ADD, UPDATE, and DELETE using LINQ with Entity Model

首先按照以下步骤添加 Entity 模型。

Step 1 − 右键单击项目,然后单击添加新项目,将打开如下图所示的窗口。选择 ADO.NET Entity Data Model,指定名称,然后单击添加。

linq entities 1

Step 2 − 选择 Generate from database.

linq entities 2

Step 3 − 从下拉菜单中选择数据库连接。

linq entities 3

Step 4 − 选择所有表。

linq entities 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 entities 5

LINQ - Lambda Expressions

术语“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

Expression Lambda

由于 lambda 表达式语法中的表达式位于右侧,因此它们也被称为表达式 lambda。

Async Lambdas

通过使用 async 关键字结合异步处理创建的 lambda 表达式称为异步 lambda。以下是一个异步 lambda 示例。

Func<Task<string>> getWordAsync = async()⇒ “hello”;

Lambda in Standard Query Operators

查询运算符中的 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

Type Inference in Lambda

在 C# 中,类型推断在各种情况下得到了方便的使用,甚至无需显式指定类型。然而,在 lambda 表达式的情况下,类型推断仅在编译器必须满足时才起作用,前提是每个类型都已指定。我们来看一下下面的示例。

delegate int Transformer (int i);

这里,编译器利用类型推断根据 Transformer 的参数类型来利用 x 是一个整数这一事实。

Variable Scope in Lambda Expression

在 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

Expression Tree

Lambda 表达式广泛用于 Expression Tree 构造。表达式树将代码赠送给类似树的数据结构,其中每个节点本身就是表达式,比如方法调用或二进制运算,比如 x<y。以下是一个用于构造表达式树的 lambda 表达式使用示例。

Statement Lambda

还有包含两个或三个语句的 statement lambdas ,但未用于构造表达式树。必须在语句 lambda 中编写 return 语句。

语句 lambda 的语法

(params)⇒ {statements}

Example of a statement 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 查询中的参数,永远不允许像 isas 一样放在运算符的左侧,就像匿名方法一样。虽然 Lambda 表达式很像匿名方法,但它们完全不受限于仅用作委托。

Points to remember while using lambda expressions

  1. Lambda 表达式可以返回值并且可能有参数。

  2. 可以通过多种方式在 lambda 表达式中定义参数。

  3. 如果 lambda 表达式中只有一条语句,则不需要花括号,但如果有多条语句,则必须编写花括号以及返回值。

  4. 借助一个称为闭包的特性,lambda 表达式可以访问 lambda 表达式块外部存在的变量。应谨慎使用闭包,以避免出现任何问题。

  5. 不可能在任何 lambda 表达式中执行任何不安全代码。

  6. Lambda 表达式不得用于运算符的左侧。

LINQ - ASP.Net

作为一组 .NET 框架扩展,LINQ 是 ASP.NET 开发人员用于数据访问的首选机制。ASP.NET 3.5 有一个内置的工具 LINQDataSource 控件,可轻松在 ASP.NET 中使用 LINQ。ASP.NET 使用上述控件作为数据源。现实生活中的项目大多包含网站或 Windows 应用程序,因此为了更好地理解 LINQ 和 ASP.NET 的概念,让我们从创建利用 LINQ 特性的 ASP.NET 网站开始。

为此,必须在您的系统上安装 Visual Studio 和 .NET 框架。在您打开 Visual Studio 后,转到“文件”→“新建”→“网站”。将打开一个弹出窗口,如下图中所示。

linq asp.net1

现在,在左侧的模板下,将有两个用于创建网站的语言选项。选择 Visual C# 并选择 ASP.NET Empty Web Site

选择您想要将新网站保存在系统中的文件夹。然后按 OKSolution Explorer ,出现包含所有 Web 文件的屏幕。在项目资源管理器中右键单击 Default.aspx,然后选择“在浏览器中查看”在浏览器中查看默认的 ASP.NET 网站。不久后,您的新 ASP.NET 网站将在网络浏览器中打开,如下面的屏幕截图所示。

linq asp.net2

LINQDataSource Control

aspx is in fact the major file extension used in ASP.NET websites. Visual Studio by default creates all the necessary pages for a basic website like Home page and About Us page where you can place your content conveniently. The code for the website is generated automatically here and can be viewed too.

可以通过 LINQDataSource 控件,以 UPDATE, INSERTDELETE 的方式在 ASP.NET 网站的页面中添加数据。绝对不需要指定 SQL 命令,因为 LINQDataSource 控件使用动态创建的命令执行此类操作。

控件允许用户通过标记文本中的属性设置方便地在 ASP.NET 网页中使用 LINQ。LINQDataSource 与 SqlDataSource 以及 ObjectDataSource 等控件非常相似,因为它可以用来将页面上其他 ASP.NET 控件绑定到数据源。因此,我们必须有一个 database 来解释 LINQDataSource 控件调用的各种函数。

在开始解释在 ASP.NET 网页表单中使用控件之前,必须打开 Microsoft Visual Studio 工具箱并将 LINQDataSource 控件拖放到 ASP.NET 网站的 .aspx 页面中(如下图所示)。

linq asp.net3

下一步是通过选择员工记录的所有列来配置 LINQDataSource。

linq asp.net4

现在将 GridView 控件添加到 .aspx 页面并像下图中所示一样对其进行配置。GridView 控件功能强大且具有灵活的数据处理能力。在配置控件后,它将出现在浏览器中。

linq asp.net5

现在可以在您的屏幕上看到 .aspx 页面的编码,如下所示:

<!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>

这里应注意,将 ContextTypeName 属性设置为表示数据库的类的属性至关重要。例如,这里给出的 LINQWebApp1.AdventureWorksDataContext 将使 LINQDataSource 和数据库之间建立所需的连接。

INSERT, UPDATE, and DELETE data in ASP.NET Page using LINQ

在严格执行所有上述步骤后,从 LINQDataSource Control 中选择 LINQDataSource Tasks 选择 all three boxes用于启用插入、更新和删除,如下图所示。

linq asp.net6

很快,声明性标记将以以下方式显示在您的屏幕上。

<asp:LINQDataSource
   ContextTypeName = "LINQWebApp1.AdventureWorksDataContext"
   TableName = "Contacts"
   EnableUpdate = "true"
   EnableInsert = "true"
   EnableDelete = "true"
   ID = "LINQDataSource1"
   runat = "server">
</asp:LINQDataSource>

由于有多行和多列,因此最好在 .aspx 表单上添加另一个控件,将其命名为“详细信息”或“主控件”(位于网格视图控件下方),以仅显示网格中所选行的详细信息。从详细信息控件中选择详细信息任务,并选择复选框,如下所示。

linq asp.net7

现在,只需保存更改并按 Ctrl+F5 即可在浏览器中查看页面,现在可以在详细信息控件上删除、更新和插入任何记录。