Transcript
Page 1: 第 18 章  数据访问的新利器 —— 语言集成查询技术

1

第第 1818 章 数据访问的新利器章 数据访问的新利器————语言集成查询技术语言集成查询技术

语言集成查询( Language Integrated Query , LINQ)是Visual Studio 2008 和 .NET Framework 3.5版中一项突破性的创新,它在对象领域和数据领域之间架起了一座桥梁。传统上,针对数据的查询都是以简单的字符串表示,而没有编译时类型检查或 IntelliSense支持。此外,还必须针对不同的数据源学习不同的查询语言,如 SQL数据库、 XML文档、各种Web服务等。而 LINQ引入了标准的、易于学习的查询和更新数据模式,可以对其技术进行扩展以支持几乎任何类型的数据存储。 Visual Studio 2008包含 LINQ Privider的程序集,这些程序集支持将LINQ 与 .NET Framework集合、 SQL Server数据库、 ADO.NET数据集和 XML文档一起使用。

Page 2: 第 18 章  数据访问的新利器 —— 语言集成查询技术

2

章节内容章节内容18.1 什么是 LINQ18.2 学习写自己的 LINQ查询18.3 LINQ to SQL

Page 3: 第 18 章  数据访问的新利器 —— 语言集成查询技术

3

18.1 18.1 什么是什么是 LINQLINQLINQ,是语言集成查询( Language

Integrated Query)的简称,是 Visual Studio 2008 和 .NET Framework 3.5版中一项突破性的创新。MicroSoft宣称 LINQ在对象领域和数据领域之间架起了一座桥梁。

Page 4: 第 18 章  数据访问的新利器 —— 语言集成查询技术

4

首先要说明什么是查询首先要说明什么是查询查询是一种从数据源检索数据的表达式。现在,我们的程序中控制的数据可以属于不同的数据域。

例如,一个数组,一个对象图表( object graph),一个 XML文件,一个数据库,一个文本文件,一个注册表值,一封电子邮件,简单对象访问协议( Simple Object Access Protocol)信息内容,一个微软的 Excel表格等等,举不胜举。

Page 5: 第 18 章  数据访问的新利器 —— 语言集成查询技术

5

不同数据域有不同的访问方法不同数据域有不同的访问方法当查询一个数据库时,我们会很自然地就用

SQL。当访问 XML数据时,很自然地就用DOM或者

XQuery。为了定位某个对象图,遍历一个数组并且构建自己的算法。

使用特定的应用程序( APIs)来访问其他的数据域,比如说Office 的 Excel表格,

最终的结果是,在访问不同的数据源时就有了不同的编程模型。

Page 6: 第 18 章  数据访问的新利器 —— 语言集成查询技术

6

LINQLINQ 试图统一这些不同数据源的试图统一这些不同数据源的不同访问方法!不同访问方法!LINQ是一个编程模型,无论是访问文件、 XML、数据库、注册表、事件日志、活动目录,还是第三方的数据,都可以使用统一的方法进行访问。

LINQ可以与所有不同形态、不同大小的数据一起工作,允许在所有这些数据上执行查询、设置和转换。

而且 LINQ是集成在 .NET编程语言中的一种特性,已经成为编程语言的一个组成部分。

Page 7: 第 18 章  数据访问的新利器 —— 语言集成查询技术

7

事实上,第 10章介绍的 Visual Studio.Net 2008在语言方面的新特性,包括扩展方法、匿名类型、 Lambda表达式、查询表达式等,大部分都是为了支持 LINQ而做出的。

Page 8: 第 18 章  数据访问的新利器 —— 语言集成查询技术

8

LINQLINQ 查询操作查询操作由以下 3 个不同的操作步骤组成。

◦获取数据源。◦创建查询。◦执行查询。

而这 3 个步骤,实际上都是由 LINQ提供程序来完成的。

Page 9: 第 18 章  数据访问的新利器 —— 语言集成查询技术

9

44 种提供程序种提供程序LINQ to SQLLINQ to XMLLINQ to ObjectsLINQ to DataSet

Page 10: 第 18 章  数据访问的新利器 —— 语言集成查询技术

10

18.2 18.2 学习写自己的学习写自己的 LINQLINQ查询查询18.2.1 第一个 LINQ查询1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load2 Label1.Text = ""3 ' 数据源4 Dim numbers As Integer( ) = {0, 1, 2, 3, 4, 5, 6}5 ' 创建查询(获取索引号为偶数的元素)6 Dim numQuery = From num In numbers _7 Where num Mod 2 = 0 _8 Select num9 ' 执行查询10 For Each num In numQuery11 Label1.Text &= num & vbCrLf12 Next13 End Sub

Page 11: 第 18 章  数据访问的新利器 —— 语言集成查询技术

11

此示例将一个整数数组 numbers用作数据源◦numQuery:查询变量,其本身不执行任何操作并且不返回任何数据。它只是存储在以后某个时刻执行查询时为生成结果而必需的信息。

◦from子句:指定数据源。◦num:范围变量,表示数据源的后继元素◦where子句:应用筛选器。◦select子句:指定返回的元素的类型。

Page 12: 第 18 章  数据访问的新利器 —— 语言集成查询技术

12

查询变量查询变量在 LINQ中,查询变量是任何存储查询而不是查询结果的变量。◦更具体地说,查询变量始终是一个可枚举的类型,当在 For each语句中或对其IEnumerator.MoveNext方法的直接调用中循环访问它时,它将产生一个元素序列。

上一个例子中的 numQuery就是一个查询变量,简称查询。

Page 13: 第 18 章  数据访问的新利器 —— 语言集成查询技术

13

查询表达式查询表达式查询表达式是用查询语法表示的查询。

由一组用类似于 SQL 或 XQuery的声明性语法编写的子句组成。每个子句又包含一个或多个表达式,而这些表达式本身又可能是查询表达式或包含查询表达式。

Page 14: 第 18 章  数据访问的新利器 —— 语言集成查询技术

14

查询表达式语法查询表达式语法查询表达式必须以 From子句开头,并且必须以 Select 或 Group子句结尾。

在第一个 From子句和最后一个 Select或 Group子句之间,查询表达式可以包含一个或多个可选子句:Where 、 Orderby 、 Join 、 Let 甚至附加的 From子句。

还可以使用 Into 关键字使 Join 或 Group子句的结果能够充当同一查询表达式中附加查询子句的源。

Page 15: 第 18 章  数据访问的新利器 —— 语言集成查询技术

15

作用 子句 说明

Destination :目标 Dim < 变量 > = 使用类型推理来

赋值

Source:源 from <项目 > in <数据源>

信息源提供一套项目

Filter:过滤器 where <表达式>, distinct 表达式指定选择的标准

Order:排序 order by < 表达式 >, < 表达式> [ 升序 | 降序 ] 控制结果的排序

Aggregate:合计

count([< 表 达 式>]) , sum(< 表 达 式>) , min(< 表 达 式>) , max(< 表 达 式>) , avg(<表达式>)

合计源项目

Projection:投影 select <表达式> 构造输出内容

Page 16: 第 18 章  数据访问的新利器 —— 语言集成查询技术

16

FromFrom 子句:指定数据源子句:指定数据源From element [ As type ] In collection [ _ ]

[, element2 [ As type2 ] In collection2 [ , ... ] ]◦ element是必需的,这是一个范围变量,用于循

环访问集合的元素,必须为可枚举类型。该范围变量用于在查询循环访问 collection时,引用collection的每个成员。

◦ type是可选的,用于指明 element的类型。如果不指定 type,则根据 collection 推断element的类型。

◦ collection是必需的。这是引用要查询的集合,必须为可枚举类型。

Page 17: 第 18 章  数据访问的新利器 —— 语言集成查询技术

17

WhereWhere 子句:筛选数据子句:筛选数据Where子句用于执行筛选,筛选器指定要在结果序列中包含数据源中的哪些元素。Where子句的语法格式如下。◦Where condition

其中, condition是一个表达式,该表达式的计算结果必须为 Boolean值或Boolean值的等效值。如果条件的计算结果为 True,则在查询结果中包含该元素;否则从查询结果中排除该元素。

Page 18: 第 18 章  数据访问的新利器 —— 语言集成查询技术

18

Order ByOrder By 子句:对数据进行排子句:对数据进行排序序

Order By orderExp1 [ Ascending | Descending ] [, orderExp2 [...] ]◦其中, orderExp1是必需的,这是当前查询结果中的一个或多个字段,用于标识对返回值进行排序的方式,字段名称必须以逗号( ,)分隔;

◦使用 Ascending 或 Descending 关键字可以指定对每个字段进行升序或降序排序。如果未指定 Ascending 和 Descending关键字,则默认排序顺序为升序。排序顺序字段的优先级从左到右依次降低。

Page 19: 第 18 章  数据访问的新利器 —— 语言集成查询技术

19

SelectSelect 子句:选择数据子句:选择数据Select [ var1 = ] fieldName1 [, [ var2 = ]

fieldName2 [...] ]其中, var1是可选的,可用于引用列表达式的结果的别名; fieldName1是必需的,是要在查询结果中返回的字段的名称。

Page 20: 第 18 章  数据访问的新利器 —— 语言集成查询技术

20

Group ByGroup By 子句:对数据进行分子句:对数据进行分组组Group [ listField1 [, listField2 [...] ] By

keyExp1 [, keyExp2 [...] ]

Into aggregateList◦listField1,listField2是可选的,用于指明查询变量的一个或多个字段,这些查询变量显式标识要包括在分组结果中的字段。如果未指定任何字段,则查询变量的所有字段都包括在分组结果中。

Page 21: 第 18 章  数据访问的新利器 —— 语言集成查询技术

21

◦keyExp1是必需的,这是一个表达式,标识用于确定元素的分组的键。可以指定多个键来指定一个组合键。

◦keyExp2是可选的,是一个或多个附加键,与 keyExp1组合在一起,创建一个组合键。

◦aggregateList是必需的,是一个或多个表达式,标识如何对组进行聚合。若要为分组结果标识一个成员名称,可以使用Group 关键字。

Page 22: 第 18 章  数据访问的新利器 —— 语言集成查询技术

22

LetLet 子句:存储查询结果子句:存储查询结果Let variable = expression [, ...]其中, variable是必需的,这是一个

别名,可用于引用所提供的表达式的结果; expression是必需的,这是一个将进行计算并赋值给指定变量的表达式。

Page 23: 第 18 章  数据访问的新利器 —— 语言集成查询技术

23

执行查询执行查询查询执行与查询创建是分开的。创建查询后,其执行由不同的机制触发。◦可在定义查询后立即执行查询(立即执行)◦也可以存储查询定义,并在以后执行查询(

延迟执行)。

Page 24: 第 18 章  数据访问的新利器 —— 语言集成查询技术

24

立即执行立即执行默认情况下,创建查询后,查询本身并不立即执行。相反,查询定义将存储在用于引用查询结果的变量中。当以后在代码中访问查询结果变量时(如在For…Next 循环中),将执行该查询,此过程称为延迟执行。之前我们看到的例子都是延迟执行方式。

Page 25: 第 18 章  数据访问的新利器 —— 语言集成查询技术

25

延迟执行延迟执行查询还可以在定义后执行,这称为立

即执行。立即执行可以通过应用要求访问查询结果的各个元素的方法来触发,这是包含聚合函数(如 Count 、 Sum、 Average 、 Min 或 Max)的结果。

Page 26: 第 18 章  数据访问的新利器 —— 语言集成查询技术

26

18.3 LINQ to SQL18.3 LINQ to SQLLINQ to SQL 全称为基于关系数据的 .NET语言集成查询,是 .NET Framework 3.5版的一个组件,提供了用于将关系数据作为对象管理的运行时基础结构。

Page 27: 第 18 章  数据访问的新利器 —— 语言集成查询技术

27

LINQ to SQL编程接口集中在System.Data.Linq.dll程序集中,要想使用 LINQ to SQL,必须在项目中引用该程序集,命名空间为“ System.Data.Linq”。

Page 28: 第 18 章  数据访问的新利器 —— 语言集成查询技术

28

示例数据库结构示例数据库结构

Page 29: 第 18 章  数据访问的新利器 —— 语言集成查询技术

29

18.3.1 18.3.1 创建对象模型创建对象模型创建 LINQ to SQL对象模型是使用

LINQ to SQL的第一步,也是最重要的一步。对象模型实际是数据库的一个映射关系和操作集合。

LINQ to SQL对象模型 关系数据模型

实体类 表

类成员 列(字段)

关联 外键关系

方法 存储过程或函数

Page 30: 第 18 章  数据访问的新利器 —— 语言集成查询技术

30

33 种创建对象模型的方式种创建对象模型的方式( 1 )对象关系设计器。( 2 ) SQLMetal 代码生成工具。( 3 )代码编辑器。

Page 31: 第 18 章  数据访问的新利器 —— 语言集成查询技术

31

第一种方式第一种方式首先需要建立与数据库的连接。可以单击菜单栏中的【工具】→【连接到数据库】来连接到你的数据库或者在【服务器资源管理器】窗口中建立数据库连接。

Page 32: 第 18 章  数据访问的新利器 —— 语言集成查询技术

32

之后,单击菜单栏中的【项目】→【添加新项】命令,打开【添加新项 -LINQtoSQLExample 】窗口,在【模板】列表框中选择【 LINQ to SQL类】,在【名称】文本框中输入“ Student.dbml”。

其中,扩展名 dbml的全称为Database Mark Language,即数据库描述语言,是一种 xml格式的文档,用来描述数据库。

Page 33: 第 18 章  数据访问的新利器 —— 语言集成查询技术

33

Page 34: 第 18 章  数据访问的新利器 —— 语言集成查询技术

34

单击【添加】按钮以后,读者会看到dbml文件的窗口与以前我们所见到的设计窗口有些不一样。

该设计窗口分了两部分:左边是数据类的可视化窗口,右边是方法的创建窗口

Page 35: 第 18 章  数据访问的新利器 —— 语言集成查询技术

35

我们将 StudentInfo表从【服务器资源管理器】窗口中直接拖曳到右边的数据类可视化窗口,即可创建一个数据类。

Page 36: 第 18 章  数据访问的新利器 —— 语言集成查询技术

36

查看代码可以看到,生成了一个StudentInfoDataContext类。该类继承自继承自 System.Data.Linq.DataContext。

DataContext类是一个 LINQ to SQL类,它充当 SQL Server数据库与映射到该数据库的LINQ to SQL实体类之间的管道

生成的实体类代码如下。1 Partial Class StudentInfoDataContext2 3 End Class

Page 37: 第 18 章  数据访问的新利器 —— 语言集成查询技术

37

18.3.2 18.3.2 获取数据获取数据下面代码是窗体的 Load事件过程,使用 LINQ获取数据并输出。1 Imports System.Data.Linq2 Public Class Form13 4 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load5 ' 实例化 LINQ to SQL对象 6 Dim db As New StudentInfoDataContext( )7 ' 得到一个表8 Dim studentList As Table(Of StudentInfo) = db.GetTable(Of StudentInfo)( )9 ' LINQ查询10 Dim query = From student In studentList _11 Select student.StuNum, student.StuName12 ' 输出13 For Each student In query14 Label1.Text &= "学号 = " & student.StuNum & ", 姓名 = " & _15 student.StuName & vbCrLf16 Next17 End Sub18 End Class

Page 38: 第 18 章  数据访问的新利器 —— 语言集成查询技术

38

使用 DataGridView控件来进行数据显示。

1 ' 实例化 LINQ对象 2 Dim db As New StudentInfoDataContext()3 ' 得到一个表4 Dim studentList As Table(Of StudentInfo) = db.GetTable(Of StudentInfo)()5 ' LINQ查询6 Dim query = From student In studentList _7 Select student.StuNum, student.StuName8 ' 绑定数据源9 DataGridView1.DataSource = query

Page 39: 第 18 章  数据访问的新利器 —— 语言集成查询技术

39

18.3.3 18.3.3 添加数据添加数据如果想要往数据库表中添加一条记录,只要向已创建的表对象模型添加一个新学生对象,然后调用StudentInfoDataContext对象的SubmitChanges方法即可。

Page 40: 第 18 章  数据访问的新利器 —— 语言集成查询技术

40

下面代码实现了记录的添加。1 Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As _2 System.EventArgs) Handles btnAdd.Click2 Dim db As New StudentInfoDataContext( )3 ' 新学生4 Dim newStudent As New StudentInfo5 newStudent.StuNum = "20083201"6 newStudent.StuName = " 李克 "7 ' 将新学生添加到 Insert 命令中8 db.StudentInfo.InsertOnSubmit(newStudent)9 ' 执行10 db.SubmitChanges( )11 End Sub

Page 41: 第 18 章  数据访问的新利器 —— 语言集成查询技术

41

18.3.4 18.3.4 更新数据更新数据如果要更新某一条记录内容,首先需

要检索到该项,然后直接在对象模型中编辑它。在修改了该对象之后,调用StudentInfoDataContext对象的SubmitChanges方法以更新数据库。

Page 42: 第 18 章  数据访问的新利器 —— 语言集成查询技术

42

下面代码实现记录的更新。1 Dim db As new StudentInfoDataContext( )2 ' 找到要修改的记录3 Dim studentToUpdate = _4 from stu in db.StudentInfo _5 where stu.StuNum="20083201" _6 select stu7 ' 对找到的记录进行修改8 for each student in studentToUpdate9 student.Sex = " 男 "10 student.Age=2111 student.Major="数学 "12 student.Class="0821"13 Next14 ' 提交修改15 db.SubmitChanges( );

Page 43: 第 18 章  数据访问的新利器 —— 语言集成查询技术

43

18.3.5 18.3.5 删除数据删除数据如果要删除某条记录,要先从其所属集合中移除,然后调用StudentInfoDataContex对象的SubmitChanges方法以提交所做的更改。注意, LINQ to SQL无法识别级联删除操作。

Page 44: 第 18 章  数据访问的新利器 —— 语言集成查询技术

44

下面代码实现记录的删除。

1 Dim db As new StudentInfoDataContext( )2 ' 找到要删除的记录3 Dim studentToUpdate = _4 from stu in db.StudentInfo _5 where stu.StuNum= "20080002" _6 select stu7 ' 如果找到了符合条件的记录则进行删除8 for each student in studentToUpdate9 db.StudentInfo.DeleteOnSubmit(student)10 Next11 ' 提交删除12 db.SubmitChanges( )