65.9K
CodeProject 正在变化。 阅读更多。
Home

学习 LINQ:LINQ to SQL 提供程序

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2012年7月9日

CPOL

11分钟阅读

viewsIcon

19923

LINQ to SQL 提供程序简介。

引言

LINQ 是 Language-INtegrated Queries 的缩写,它基本上使查询成为 C# 和 VB.NET 等 .NET 语言的一等公民(即,使它们在 Visual Studio 2008 的 IntelliSense 中可用)。

我们可以将 LINQ 与任何数据源一起使用。我们可以用我们选择的编程语言表达高效的查询行为,可选地将数据查询结果转换/整形为我们想要的任何格式,然后轻松地操作结果。启用 LINQ 的语言可以提供完整的类型安全和查询表达式的编译时检查,开发工具可以在编写 LINQ 代码时提供完整的 IntelliSense、调试和丰富的重构支持。

Using the Code

为什么我们需要 LINQ?

当开发人员接触到 LINQ 时,会想到一些基本问题:

  • 为什么我们需要 LINQ 这样的工具?
  • 以前的工具为什么不方便?
  • LINQ 的创建只是为了使同时使用编程语言、关系数据和 XML 更方便吗?

回答这些问题肯定能让我们看到 LINQ 项目的重要性并欣赏它。众所周知,绝大多数开发的应用程序都访问数据或与关系数据库通信。要编程此类应用程序,学习 C# 等语言是不够的。我们需要学习另一种语言,如 SQL,以及将其与 C# 结合形成应用程序的 API。

LINQ 项目解决了 **数据!= 对象** 的问题,涉及关系数据、XML 数据等所有领域。这些领域的数据完全不同,最初并非为完全兼容地协同工作而创建。此外,我们现在使用面向对象语言通过对象访问和操作这些领域的数据,而对象是另一个完全不同的领域。因此,我们看到不同的数据存储之间存在严重的匹配或不兼容问题,而现在它们正变得相互依赖。

为了证实我们上面讨论的内容,让我们考虑关系数据与对象世界不兼容的场景。

  1. 关系数据库和面向对象语言的数据类型行为不同。
  2. 出于性能原因,数据库使用范式化,这导致数据的组织方式特定于关系数据模型。对象的组织基于继承、组合和复杂引用图的概念。数据库没有继承等概念。因此,由于这两个世界的模型本身就不同,因此弥合它们之间的差距变得困难。
  3. 编程模型不同。在 SQL 中,我们为所需数据编写精确的查询。如果我们在 C# 中想要相同的结果,我们必须遍历集合并执行一些条件操作,然后收集结果。因此,编程模型也不同。
  4. 在面向对象语言中,我们看到对象将数据和行为作为单个实体包含在自身中。这与关系模型截然不同,在关系模型中,数据与代码完全分离。

问题的实际示例

让我们看一个实际的代码示例,看看这两个世界有多么不同

.NET 框架类库包含一个名为 ADO.NET 的 API,用于访问关系数据库并在内存中表示关系数据。此 API 包含 SqlConnection、SqlCommand、SqlDataAdapter、SqlDataReader 等类。这些类的问题在于它们强制开发人员显式地处理表、记录和列,而 C# 和 VB.NET 等现代语言使用面向对象范例。

LINQ 通过消除编写大量用于将面向对象模型映射到关系数据库或 XML 的管道代码的负担,帮助我们提高数据密集型编程的生产力。

考虑下面这段用 .NET 编写的连接数据库的代码片段

SqlConnection MyCon = new SqlConnection("Data Source = X; Initial Catalog =Y ; User ID = Z; Password=***"); 
SqlCommand MyComm = new SqlCommand(); 
MyComm.CommandText = @"Select Name,CustomerID FROM Customers WHERE City =@City"; 
MyComm.Parameters.AddWithValue("@City", "Mysore"); 
MyCon.Open(); 
MyReader = MyComm.ExecuteReader(); 
if (MyReader.HasRows) 
{ 
	string NameCustomer = MyReader.GetString(0); 
	//Additional code omitted// 
} 
else 
{ 
	MessageBox.Show("Sorry No Data"); 
}

关于上述代码,我们可以注意到以下几点:

  1. 为实现一个简单功能编写了几个步骤
  2. 编写的查询只是普通字符串,因此在编译时不会被验证为查询,而是作为字符串。即使查询语法不正确,它也会通过所有编译检查
  3. 参数定义松散。例如,此处定义的列类型可能与服务器上的不同。在编译时无法检查这一点。
  4. 如果使用 DBxxx 类进行与提供程序无关的代码,则在此模型中无法使用特定于提供程序的方言或代码。

在这里我们看到了现有模型的局限性。那么答案是什么?

在 LINQ 中寻找解决方案

LINQ 旨在将数据查询和操作语言的功能深度集成到编程语言中。LINQ 消除了对象、数据库和 XML 之间的障碍。它使我们能够使用相同的语言集成工具来处理它们。例如,现在我们可以在同一个查询中处理来自关系数据库的数据和来自 XML 的数据。LINQ 使这变得容易。

我们获得的一些出色好处是:

  1. 查询在编译时检查。我们不再需要等到运行时才能检测到查询中的错误。
  2. 编写 LINQ 查询时,我们可以获得 Visual Studio 的 IntelliSense,这使得编码更快。

让我们看看 LINQ 的一些设计目标。

目标

动机

集成对象、关系数据和 XML

需要针对不同语言和数据源的统一查询语法,以及需要单一处理模型。

在 C# 和 VB 中拥有 SQL 和 XQuery 的强大功能

将查询功能直接集成到编程模型中

语言的可扩展性模型

使其他编程语言得以实现

类型安全

编译时检查以避免问题

调试器支持

-

关于 LINQ 的两种观点?

LINQ 可以被认为是两个互补的部分:

  1. 一组用于处理数据的工具
  2. 一组编程语言扩展

LINQ 作为一套工具

LINQ 确实改变了应用程序和组件处理和操作数据的一些方面。LINQ 中提供了一组提供程序供开发人员使用。这些提供程序包括 LINQ to Objects、LINQ to XML、LINQ to DataSet、LINQ to SQL、LINQ to Entities 等。所有这些提供程序都建立在一个共同的基础之上,该基础由查询运算符、查询表达式和表达式树等构建块组成。这些构建块使 LINQ 工具具有可扩展性。可以创建 LINQ 的其他变体以提供对各种数据源的访问。可以将文件系统、ActiveDirectory、Windows 管理规范 (WMI)、Windows 事件日志或任何其他数据源或 API 等各种数据源插入到 LINQ 中。

LINQ 作为一组编程语言扩展

LINQ 提供程序绝不是独立的工具。它们可以直接用于任何 .NET 编程语言。LINQ 允许我们通过针对各种数据源编写查询来访问信息。我们都非常熟悉编写 SQL 查询。即使在当今的数据访问技术中,我们仍然坚持在编程语言中编写查询,但使用特定于源的语法。LINQ 提供了与 SQL 相同的表达能力,但使用的是我们选择的编程语言。这使我们能够编写更短、更简洁的代码。例如,关键字 from、where、orderby、select 等现在已成为 C# 的一部分。这告诉我们 C# 已扩展以支持语言集成查询。

让我们开始吧

让我们开始深入了解 LINQ to SQL 并从数据库中读取数据。

步骤 1:在数据库中创建一个表

我已在此示例中在名为 MyServer 的服务器上名为 MyDatabase 的数据库中创建了一个名为 Parcel 的表。我将用于登录 MSSQL Server 2005 (MyServer) 的用户凭据是:

用户 ID:Arpan_Patro

密码:infy@123

Parcel 表的简要描述如下。

列名

列 ID

ParcelID(主键)

Varchar(5)

状态

Varchar(10)

ArriveCode

Int

步骤 2:在 Visual Studio 2008 中打开一个新的控制台应用程序

步骤 3:包含必要的命名空间

既然我们想用 Visual Studio 做一些新的事情,我们需要添加一些新的命名空间。这些命名空间已经添加到 VS2008 版本中。

using System.Data.Linq.Mapping; 
using System.Linq; 
using System.Data.Linq;

注意:如果命名空间未通过 IntelliSense 出现,您可能需要手动添加 System.Data.Linq 命名空间,然后尝试通过 IntelliSense 获取命名空间。

一个显而易见的问题随之而来:“我为什么需要这些,或者我通过添加这些命名空间获得了什么?”

我们将在接下来的步骤中探讨原因。

步骤 4:创建类(使用属性 Table 和 Column)

在此步骤中,我们使用 C# 语言创建表示数据库中对象的对象。通过用属性装饰普通类,对象与关系数据链接。两个最重要的属性是 Table 和 Column。

Table 属性用于修饰类。它的一个属性是 Name;它用于指定类对象所链接的表的名称。如果 Name 属性缺失,则类的名称将用作表的名称。用 Table 属性修饰的类称为*实体类*,实体类的一个实例称为实体。只有实体存储在数据库中。

例如:在我的示例中,我有一个名为 Parcel 的表,因此在 *Program.cs* 文件中,我编写了以下代码:

[Table(Name = "Parcel")] 
public class Parcel 
{ 
………..

Column 属性用于修饰实体类的字段或属性,以将它们与表的列关联起来。Column 属性也有几个属性,其中之一是 Name 属性。与 Table 的 Name 属性类似,它用于指定实体类的字段或属性所匹配的表中的字段。如果未指定此属性,则实体类的字段或属性的名称将被假定为表中字段的名称。

在我的示例中,我有三个列,我将其指定如下:

[Table(Name = "Parcel")] 
public class Parcel 
{ 
[Column] 
public string ParcelID; 
[Column] 
public string Status; 
[Column] 
public int ArriveCode; 
}

重要的是要知道 Table 和 Column 属性存在于 System.Data.Linq.Mapping 命名空间中。

步骤 5:创建 DataContext

简单来说,DataContext 是一种将查询传递给关系数据库的方式。它负责将我们的 LINQ 查询翻译成适当的 SQL 查询,并与指定的数据库通信。它的行为类似于 ADO.NET 中的 Connection 对象。我们必须将连接字符串传递给 DataContext 类的构造函数。这使得在当前数据上下文(稍后解释)中执行的 LINQ 查询能够在给定连接字符串指定的数据库上执行。

创建表和列后,我们现在将创建 DataContext,如下所示,提供您自己的凭据、服务器名称。

[Database(Name = "MyDatabase")] 
public class MyDataBase : DataContext 
{ 
public Table<parcel> Parcel; 
public MyDataBase() 
: base("Data Source = MyServer ; Initial Catalog = MyDatabase ; User ID = Arpan_Patro ; Password = infy@123") 
{ } 
}</parcel>

DataContext 类位于 System.Data.Linq 命名空间中。

您可以将 Database 属性应用于任何强类型 DataContext 声明。

Database 属性是可选的。如果使用它,则必须使用 Name 属性提供一个名称。

如果您不应用此属性且连接未指定名称,则假定数据库与 DataContext 类同名。

我们上面所做的不仅仅是创建一个数据上下文,我们还对数据库进行了建模,并将我们之前创建的表类指定为这里的表(注意这里使用了泛型)。

步骤 6:编写 LINQ 查询

成功完成步骤 1 到 5 后,我们现在将按照以下方式在主方法中编写 LINQ 查询:

static void Main(string[] args) 
{ 
MyDatabase MyConnection = new MyDatabase(); 
//This is the LINQ Query for fetching all the records from the Parcel Table 
var Result = from myLinQ in MyConnection.Parcel 
select new{ 
myLinQ.ParcelID, myLinQ.Status, myLinQ.ArriveCode}; 
//Displaying the Query Output onto the Console 
foreach (var NewRow in Result) 
{ 
  Console.WriteLine("{0,-25} {1,-10}”+ “{2}", 
      NewRow.ParcelID.ToString(), 
      NewRow.Status.ToString(),NewRow.ArriveCode.ToString()); 
}

上面使用的 Var 是 C# 3.0 中的匿名类型。它会自动推断赋值操作右侧的类型并充当该类型。

如果你注意到 LINQ 查询在结构上与 SQL 查询有很大的相似之处。数据库返回的结果总是作为 IEnumerable 返回,所以我们可以使用 foreach 循环来访问结果集。

步骤 6:现在只需构建并执行

这展示了使用如此强大的工具并在 C# 中使用来自各种来源的数据编写复杂逻辑是多么容易。可以编写类似的代码来访问 XML 文件、对象、实体等中的数据。

摘要

在本文档中我们已经了解了:

  1. LINQ 在提供统一编程模型方面的重要性。
  2. LINQ 的设计目标
  3. 如何使用 LINQ to SQL 提供程序

参考资料

  1. 关键词定义来自 www.msdn.com
  2. LINQ in Action - Fabrice Marguerie, Steve Eichert 和 Jim Wooley, Manning Publications。
© . All rights reserved.