当前位置: 首页 > 文章教程  > 计算机与互联网 > 网络编程

第11章LINQtoSQL数据库操作

8/31/2020 8:49:51 PM 人评论

第11章LINQtoSQL数据库操作

第11章 LINQtoSQL数据库操作

语言集成查询(Language Integrated Query,LINQ)是Visual Studio 2008和.NET Frame-work 3.5中一个突破性的创新,它在对象和数据间架起了一座“桥梁”。

在开发一个数据库应用程序时,常规做法是由程序员编写SQL语句,然后从数据库中取出相应数据生成DataSet、DataReader等,最后绑定到表示层上。这就造成了数据库数据与表示层之间出现“紧耦合”的现象。一旦数据库结构发生变化,将造成表示层必须进行大量修改的问题,违反了“高内聚,低耦合”的设计原则。LINQ的出现使程序员找到了一种简单、有效的问题解决方案。

11.1 LINQ的概念

LINQ支持所有类型的数据源,使程序开发人员可以使用相同的语法在XML、SQLServ-er、Mysql、ADO.NET,甚至是所有支持IEnumerable或泛型IEnumerable<T>接口的对象集合等环境中执行查询操作。LINQ作为编程语言的一个组成部分,在编写程序时可以得到很好的编译时语法检查、丰富的元数据、智能感知和静态类型等强类型语言的好处。它同时还使得查询可以方便地对内存中的信息进行查询而不仅仅只是外部数据源。

LINQ定义了一组标准查询操作符,用于在所有基于.NET平台的编程语言中更加直接地声明跨越、过滤和映射操作的统一方式。标准查询操作符允许查询作用于所有基于IEnu-merable<T>接口(泛型接口)的源,并且它还允许适合于目标域或技术的第三方特定域操作符来扩大标准查询操作符集。更重要的是,第三方操作符可以用自己提供的附加服务来实现自由标准查询操作符的替换。

11.1.1 LINQ的构成

在.NET类库中,与LINQ相关的类库都在System.Linq命名空间下,该命名空间提供支持使用LINQ进行查询的类和接口,其中最重要的是下列两个类和两个接口。

1)Enumerable类:它通过对IEnumerable<T>提供扩展方法,实现LINQ标准查询运算符。包括过滤、导航、排序、查询、连接、求和、求最大值和求最小值等操作。

2)Queryable类:它通过对IQueryable<T>提供扩展方法,实现LINQ标准查询运算符。包括过滤、导航、排序、查询、连接、求和、求最大值和求最小值等操作。

3)IEnumerable<T>接口:它表示可以查询的数据集合,一个查询通常是逐个对集合中的元素进行筛选操作,然后返回一个新的IEnumerable<T>对象,用来保存查询结果。

4)IQuerable<T>接口:它继承IEnumerable<T>接口,表示一个可以查询的表达式目录树。

根据数据源类型,可以将LINQ技术分成以下4个主要技术方向。

1)LINQ to Object:数据源为实现了接口IEnumerable<T>或IQeryable<T>的内存数据集合,这也是LINQ的基础。

2)LINQ to ADO.NET:数据源为ADO.NET数据集,这里将数据库中的表结构映射到类结构,并通过ADO.NET从数据库中获取数据集到内存中,通过LINQ进行数据查询。

3)LINQ to XML:数据源为XML文档,这里通过XElement、XAttribute等类将XML文档数据加载到内存中,通过LINQ进行数据查询。

4)除了这3种常见的数据类型外,.NET 3.5还为用户扩展LINQ提供了支持,用户可以根据需要实现第三方的LINQ支持程序,然后通过LINQ获取自定义的数据源。

本章主要介绍使用LINQ to SQL实现关系型数据库访问的技术和基本操作方法。其他LINQ分支的使用方法与LINQ to SQL十分相似,涉及的语法和基本概念完全相同,读者可参考有关书籍进一步学习。

11.1.2 与LINQ相关的几个概念

在开始使用LINQ前,先来了解几个相关概念。

1.匿名类型

“匿名类型”也称为“隐式类型”或“推断类型”,如果在程序中需要用到临时类型,而又不希望去创建相应的类时,可以考虑使用匿名类型。匿名类型使用var关键字进行声明。举例如下。

var stuinfo=new{StuName="张三",StuID="2017000234",StuAge=20};

Response.Write(stuinfo.StuName.ToString());//屏幕上显示“张三”

需要说明的是,上面声明的变量stuinfo虽然没有明确地指定类型(var是关键字,不是类型),但它仍然是有类型的,只是在这里不需要关心,也不知道而已。程序运行时使用var关键字声明的匿名类型变量的具体类型由编译器根据上下文进行判断和处理。

举例如下。

vari=10; //声明一个匿名变量

intj=10; //声明一个整型变量

Response.Write(i+j); //隐式转换后输出,得到计算结果20

上述代码中声明了一个整型和一个匿名类型的变量,分别为其赋值10,输出两个变量的和,屏幕上得到“20”的计算结果。

在使用LINQ to SQL时,经常需要创建一些临时功能的新类型。例如,执行一个查询时,通常希望能返回一个类,用于存放代表一些数据库列的集合,这时使用匿名类型就显得十分方便了。

2.泛型

泛型并不是.NET Framework 4.5的新功能,但它对LINQ to SQL来说是相当重要的概念。需要注意的是,使用泛型需要引入System.Collections.Generic命名空间。

例如,下列语句声明并初始化了一个名为MyGeneric、用于表述一个字符串列表的泛型集合。

List<string>MyGeneric=new List<string>;

MyGeneric.Add("zhangsan");

MyGeneric.Add("2017000234");

MyGeneric.Add("工程机械1701");

在Visual Studio中可以将上述代码简化为如下所示。

List<string>MyGeneric=new List<string>{"zhangsan","2017000234","工程机械1701"};

由于泛型是强类型的,所以泛型集合(如List)优于非泛型集合(如ArrayList)。Ar-rayList将数据都保存为对象,在使用这些数据前需要将其转换成特定的类型。泛型则将所有数据都保存为它们特定的类型。当使用这些数据时可直接提取,而不需要进行类型转换。

3.扩展方法

使用扩展方法可以为一些现有的类增加某种特定的功能,也就是向一个现有的类中添加新的静态方法(注意必须是静态的)。创建扩展方法的语法格式如下。

978-7-111-58440-7-Chapter11-1.jpg

需要说明以下两点。

1)this关键字后面的“作用类型”表示该方法对哪个类型有效。

2)必须在顶级静态类中定义扩展方法,也就是说方法定义代码必须书写在页面public partialclass的声明之外。

例如,在对字符串的操作中有ToUpper()方法和ToLower()方法,用于将字符串变量转换为全部大写或全部小写。但是,如果希望将字符串转换成首字母大写、其他小写的格式,就没有现成的方法可以使用,此时可以考虑使用添加扩展方法的方式解决问题。

【演练11-1】为字符串(string)类型添加一个用于实现以数字字符串为半径值,输出圆面积的扩展方法。程序运行后显示如图11-1所示的页面,用户在文本框中输入了一个数字字符串后,单击“计算”按钮,在标签中将显示出以该数字字符串为半径值的圆的面积计算结果。

978-7-111-58440-7-Chapter11-2.jpg

图11-1 扩展方法使用示例

程序设计步骤如下。

(1)设计Web页面

新建一个ASP.NET网站,向页面中添加一个文本框控件TextBox1、一个按钮控件But-ton1和一个用于显示输出信息的标签控件Label1,适当调整各控件的大小及位置。

(2)设置对象属性

设置文本框的ID属性为txtR,命令按钮控件的ID属性为btnOK,标签控件的ID属性为lblResult。各控件的其他初始属性值在页面载入时通过代码进行设置。

(3)编写程序代码

1)页面载入时执行的事件代码如下。

978-7-111-58440-7-Chapter11-3.jpg

2)创建扩展方法的代码如下(ExtraClass与Web窗体类级别相同,不可将其嵌套在_Default类中)。

978-7-111-58440-7-Chapter11-4.jpg

3)“计算”按钮被单击时执行的事件代码如下。

978-7-111-58440-7-Chapter11-5.jpg

从上例中可以看到扩展方法的确十分有用,为程序员扩展现有类型的行为方面提供了充分的自由度。在使用扩展方法时应注意下列几个问题。

1)扩展方法是一种特殊的静态方法。

2)扩展方法必须在静态类中进行定义。

3)扩展方法的优先级低于同名的类方法。

4)扩展方法只能在特定的命名空间中使用。

4.Lambda表达式

Lambda表达式是.NET Framework 3.5开始提供的一个新特性,它提供了一种极为简洁的定义方法的方式。它是从.NET Framework 1.0中的“委托”和.NET Framework 2.0中的“匿名方法”过渡而来的。

(1)委托

委托实际上是一个函数指针,将问题的处理指向一个方法。例如,希望将前面介绍的字符串“首字母大写、其他小写”的实现交由委托来完成的示例代码如下。

1)定义一个委托,代码如下。

//委托名为DeleTransfer,返回值为string类型,向方法传递一个string类型的s形参

978-7-111-58440-7-Chapter11-6.jpg

2)单击“委托”按钮时调用委托实现程序功能,代码如下。

978-7-111-58440-7-Chapter11-7.jpg

(2)匿名方法

分析上述代码可以看出,在实际应用中被调用方法的具体名称无关紧要,关键是方法体的返回值。所以在.NET Framework中引入了“匿名方法”的概念。如下列代码所示,使用匿名方法无须首先创建方法,而是将方法体语句直接书写到委托实例化语句中,并用大括号将其括起来(如代码中的斜体部分)。

978-7-111-58440-7-Chapter11-8.jpg

(3)过渡到Lambda表达式

Lambda表达式是一个匿名函数,它可以包含表达式和语句块,可用于创建委托或表达式目录树类型。

所有Lambda表达式都使用Lambda运算符“=>”,该运算符读为“goes to”。该运算符的左边是输入参数(如果有的话),右边包含表达式或语句块。

具体使用方法如下列代码中的斜体部分所示。程序的功能仍然是将一个字符串的首字母变成大写,其他为小写。

978-7-111-58440-7-Chapter11-9.jpg

Lambda表达式的基本形式如下。

(参数列表)=>{表达式或语句块};

Lambda表达式与匿名方法主要的不同点在于,匿名方法中的参数必须是已定义好的,而在Lambda中的参数既可以是明确类型,也可以是匿名类型(可推断的)。

Lambda表达式的一般规则如下。

1)Lambda表达式所包含的参数数量必须与委托类型包含的参数数量相同。

2)Lambda表达式中的每个输入参数必须都能够隐式转换为其对应的委托参数。

3)Lambda表达式的返回值(如果有的话)必须能够隐式地转换为委托的返回类型。

需要说明的是,Lambda表达式本身没有类型,因为通用类型系统中没有“Lambda表达式”这一内部概念。通常所说的Lambda表达式的“类型”,是指委托类型或Lambda表达式所转换为的Expression类型。

5.对象关系设计器

对象关系设计器也称为O/R设计器,用来自动生成与数据库表对应的DataConText类。DataConText类是LINQ to SQL框架的主入口点,所有实体对象与关系型数据库中数据的转换就是依靠DataConText类来完成的。

创建DataConText类可以通过手工的方法,也可以使用O/R设计器自动完成。当向ASP.NET网站中添加一个“LINQ to SQL类”时,系统将自动打开O/R设计器。从服务器资源管理器窗口中,将数据库表、存储过程等拖动到O/R设计器中,即可自动生成需要的DataConText类或方法。

关于O/R设计器的具体用法,将在后面的例题中进行详细介绍。

11.2 使用LinqDataSource控件

在Visual Studio 2008以上版本中提供了一个名为LinqDataSource的控件,使用该控件可以非常简单地实现LINQ to SQL对数据库的访问,而且程序员几乎不用编写任何代码。使用该控件创建数据库应用程序的基本步骤如下。

1)创建DataContext类。

2)配置LinqDataSource控件。

3)配合GridView、DataList等数据控件操作数据库。

11.2.1 创建DataContext类

在Visual Studio中可以方便地使用对象关系设计器(O/R设计器),完成使用LINQ to SQL所必需的类的创建,操作时只要将数据表从服务器资源管理器中拖动到O/R设计器中即可。

例如,已经在SQL Server中创建了一个名为StudentDB的数据库,其中包含一个用于存放学生基本信息的StudentInfo表。使用O/R设计器创建DataContext类的操作方法如下。

1)向网站中添加一个LINQ to SQL类的新项。在解决方案资源管理器中右击网站名称,在弹出的快捷菜单中选择“添加”→“添加新项”命令,在弹出的如图11-2所示的对话框中选择“LINQ to SQL类”选项,并指定对应的文件名称(本例使用了系统提供的默认名称DataClasses.dbml)后单击“添加”按钮。

978-7-111-58440-7-Chapter11-10.jpg

图11-2 向网站中添加LINQ to SQL类

一般LINQ to SQL类文件需要存放在App_Code文件夹(具有访问控制特性的ASP.NET特殊文件夹)中,如果网站中尚未创建该文件夹,系统会弹出如图11-3所示的提示信息框,应单击“是”按钮。

978-7-111-58440-7-Chapter11-11.jpg

图11-3 创建App_Code文件提示信息框

2)操作完成后,屏幕自动切换到如图11-4所示的O/R设计器窗口。此时,在解决方案管理器中可以看到在App_Code文件夹中多出了一个名为DataClasses.dbml的文件,以及隶属于该文件夹的DataClasses.dbml.layout和DataClasses.dbml.cs两个文件。

从图中可以看到O/R设计器由左、右两个窗格组成,将数据表拖动到左侧窗格可以创建相应的数据类,将存储过程等拖动到右侧窗格则可创建相应的方法。设计器关闭后,可在解决方案资源管理器中,通过双击DataClasses.dbml文件的方法将其再次打开。

3)将事先准备好的StudentDB数据库及其日志文件(StudentDB.mdf和StudentDB_log.ldf)复制到网站App_Data文件中。与数据库连接成功后,在服务器资源管理器中将显示该数据库中的表、存储过程等资源,如图11-5所示。将数据表从服务器资源管理器中拖动到O/R设计器的左窗格,将出现如图11-6所示的数据表对象。

4)操作完毕后,选择“视图”→“类视图”命令,可以看到系统已成功地创建了一个名为DataClassesDataContext类和一个与数据表同名的实体类(如本例的StudentInfo类),如图11-7所示。

978-7-111-58440-7-Chapter11-12.jpg

图11-4 O/R设计器界面

978-7-111-58440-7-Chapter11-13.jpg

图11-5 数据库连接成功

978-7-111-58440-7-Chapter11-14.jpg

图11-6 O/R设计器中的表对象

978-7-111-58440-7-Chapter11-15.jpg

图11-7 由O/R设计器生成的类

上述两个类的定义内容包含在DataClasses.dbml.cs文件中,用户可以在代码视图中将其打开进行查看或修改。此外,从解决方案资源管理器中打开web.config文件,可以看到系统自动添加到其中的数据库连接字符串信息。

11.2.2 配置LinqDataSource

1)双击工具箱中的LinqDataSource控件图标将其添加到页面中,通过控件的任务菜单启动LinqDataSource的配置向导,如图11-8所示。

2)配置数据源首先需要一个用于检索或更新数据表的上下文对象,一般应选择前面创建的DataContext类对象,如本例的DataClassesDataContext,如图11-9所示。选择完毕后单击“下一步”按钮。

978-7-111-58440-7-Chapter11-16.jpg

图11-8 配置LinqDataSource的数据源

978-7-111-58440-7-Chapter11-17.jpg

图11-9 选择上下文对象

3)在“配置数据选择”对话框中,选择目标数据表、是否分组及返回数据集中包含在字段,如图11-10所示。单击Where按钮,可以在弹出的对话框中设置返回数据的筛选条件(配置Where条件表达式)。

978-7-111-58440-7-Chapter11-18.jpg

图11-10 配置数据选择

例如,希望程序运行时通过用户在文本框TextBox1中输入的信息作为按学生姓名进行查询的依据,可按如图11-11所示配置Where表达式。

978-7-111-58440-7-Chapter11-19.jpg

图11-11 配置Where属性

在“列”下拉列表框中,选择数据表字段StudentName作为筛选依据,设置“运算符”为布尔表达式中的等于“==”,在“源”下拉列表框中选择筛选关键字来自于控件(Con-trol),设置“控件ID”为TextBox1,设置完毕后单击“添加”按钮,将Where表达式设置添加到LinqDataSource1控件的Where属性中。

4)在“配置数据选择”对话框中,单击OrderBy按钮,可在弹出的对话框中设置返回数据的排序依据和排序方式(升序或降序)。

5)单击“高级”按钮,可在弹出的对话框中选择是否启用LinqDataSource控件的自动删除、插入或更新功能。

11.2.3 LinqDataSource控件使用示例

本节将以一个实例说明使用LinqDataSource控件配合FormView控件实现常规数据库操作的方法。

【演练11-2】设计一个ASP.NET空网站,向网站中添加一个Web窗体页Default.aspx。将前面使用的StudentDB数据库及其日志文件复制到网站的App_Data文件夹中。要求程序对SQLServer数据库具有查询、修改、删除和新建记录的功能。

1.设计应用程序用户界面

按照程序设计要求,在已创建了DataContext类、添加了LinqDataSource控件的基础上,再向页面中添加一个用于显示和操作数据表的FormView1。通过这些控件构成数据表操作的用户界面。

2.设置对象属性

通过LinqDataSource控件的配置向导,设置其“上下文对象”为前面创建的DataContext类,设置其数据选择为StudentalInfo表中的所有字段。单击“配置数据选择”对话框中的“高级”按钮,启用其添加、编辑和删除记录功能。

通过FormView控件的任务菜单设置其数据源为前面配置完成的LinqDataSource1,选择“启用分页”,并参照本书前面的介绍修改FromView控件的ItemTemplate、EditItemTemplate和InsertItemTemplate,模板外观如图11-12所示。

978-7-111-58440-7-Chapter11-20.jpg

图11-12 修改FormView控件的查看、修改和添加记录模板

按<F5>键运行程序,显示如图11-13所示的页面,单击分页标记可逐条查看数据记录,单击“编辑”“删除”或“新建”按钮可实现相应的数据库操作。

978-7-111-58440-7-Chapter11-21.jpg

图11-13 查看、修改和添加记录的界面

通过本例可以看出,LinqDataSource控件的使用方法与SqlDataSource、AccessDataSource等数据源控件的使用方法非常相似,程序员几乎不用编写任何代码即可实现对数据库的常规操作(如查询、插入、修改和删除)。

需要说明的是,上面介绍的方法仅适合于简单且对数据库操作没有特殊要求的应用场合。多数情况下,需要使用手工编写LINQ to SQL查询语句的方法来实现更为复杂、实用的数据库操作。

11.3 使用LINQ to SQL的对象和方法

本节将介绍使用LINQ to SQL对象直接操作数据库的相关知识。LINQ to SQL的语法格式与常用的SQL语法格式相似,也是由Select、Update、Insert和Delete等关键字组成的,但其含义却有根本上的不同。

使用LINQ to SQL进行选择,类似于SQL语言中的Select语句。其基本操作步骤如下。

1)创建DataContext类和数据表实体类,这一步骤一般可通过O/R设计器来完成。有关LINQ的其他操作这一步也是必需的,今后不再赘述。

2)实例化DataContext类。

3)使用LINQ to SQL语法创建查询。

4)输出查询结果。

11.3.1 返回数据表中的全部记录(Select语句)

在使用LINQ to SQL进行数据库操作前,必须保证已正确创建了DataContext类和数据表实体类(如本例由O/R设计器生成的DataClassesDataContext类和StudentInfo类)。

1.返回全部记录的全部列

下面代码说明了在此基础上如何使用LINQ to SQL返回数据表StudentInfo中所有数据的方法。

978-7-111-58440-7-Chapter11-22.jpg

代码的第1行声明了一个名为db的DataClassesDataContext对象,完成了DataContext类的实例化。

代码的第2行就是LINQ to SQL查询语句,可以看到与传统的SQL语句不同,它是以from子句开始,以select子句结束,而且查询结果被赋值给了一个使用var关键字声明的、名为StuInfo的匿名类型对象。from子句后面的StuTable也是一个匿名类型对象,其中存放了数据表中的所有数据,但由于StuTable对象是在LINQ to SQL语句中声明的,所以对select语句之后的语句该对象是不可见的。

代码的第3行,将匿名类型对象作为GridView控件的数据源进行了绑定,实现了查询结果的输出。

如果仅是简单地返回全部记录的全部字段,上述代码可简化为下列形式。

978-7-111-58440-7-Chapter11-23.jpg

2.返回全部记录的部分字段

如果希望只返回全部记录的部分字段值(如只返回“学号”StudentID和“电子邮件”Email),可将select子句改为如下内容。其中,new{StuTable.StudentID,StuTable.Email}语句创建了一个包含了两个属性的新匿名类型。

select new{StuTable.StudentID,StuTable.Email};

3.返回某条记录的某个字段值

下列语句表示了从查询结构中取出某行某列值的方法。语句使用ToList()方法,将sinfo转换成List<>泛型集合后,取出其中的字段值,即将查询结果中第一条记录的StudentID字段值显示到标签控件中。

978-7-111-58440-7-Chapter11-24.jpg

978-7-111-58440-7-Chapter11-25.jpg

请思考一下,如果将语句改为以下内容可以得到相同的结果吗?

Label1.Text=db.StudentInfo.ToList()[0].StudentID;

改成以下内容又如何?

Label1.Text=StuTable.ToList()[0].StudentID;

4.遍历某字段的全部值

下列代码表示了使用foreach循环遍历studentID字段,并将该字段的所有值添加到列表框控件ListBox1中的方法。

978-7-111-58440-7-Chapter11-26.jpg

11.3.2 返回数据表中符合条件的部分记录(Where语句)

Where语句用于设置查询的筛选条件,使只有符合Where表达式的记录才能出现在返回结果中。

1.使用Where语句

下列语句(斜体字部分)通过Where语句设置了条件表达式,筛选出专业为“软件技术”,且“1991-02-01”前出生的所有记录。

978-7-111-58440-7-Chapter11-27.jpg

2.使用Where()方法

通常将上面代码的编写方式称为“语句方式”,将使用Lambda表达式的编写方式称为“方法方式”,实现程序功能的方法方式代码如下所示。代码中的斜体字部分使用db.StudentInfo对象的Where()方法,并使用Lambda表达式表示了查询条件。程序的返回结果与上例完全相同。

978-7-111-58440-7-Chapter11-28.jpg

978-7-111-58440-7-Chapter11-29.jpg

3.Single()和SingleOrDefault()方法

如果希望从数据库中返回单独的一条记录,可使用Single()或SingleOrDefault()方法。

Single()方法:用于返回符合条件的单独一条记录,在没有找到任何匹配记录时将抛出一个异常。

SingleOrDefault()方法:用于返回符合条件的单独一条记录,在没有找到任何匹配记录时将返回null。

例如,有一个user数据表,包含username和userpassword两个字段,且已通过O/R设计器生成了DataContext类DataClassesUserDataContext和数据表实体类user。下列代码表示了用户登录时身份验证的实现方法,UserName和UserPwd为两个文本框控件。

978-7-111-58440-7-Chapter11-30.jpg

说明:如果网站中已存在由其他数据表通过O/R设计器生成的DataContext类,需要再次执行“添加新项”命令,向网站中添加一个新的DataContext类(如本例的DataClassesUs-erContext)。也就是说,网站中包含几个数据表就需要使用相同数量的DataContext类。

4.返回字段值包含特定字符串的记录

可以在LINQ to SQL查询中使用的字符串方法有许多,如Length、Substring、Contains、StartsWith、EndsWith和IndexOf等。这些方法的含义及使用与标准字符串方法基本相同,这里不再赘述。

下列语句可实现返回StudentInfo数据表中所有使用163邮箱的学生记录的功能,类似于SQL语句中的Like查询。语句中使用了Contains()方法来判断字段中是否包含特定字段串。

978-7-111-58440-7-Chapter11-31.jpg

11.3.3 返回数据集合的排序(OrderBy方法)

使用OrdreBy()方法或OrderByDescending()方法可以实现返回记录的升序或降序排列。例如,下列代码实现了所有学生记录按出生日期字段升序排序的功能。

978-7-111-58440-7-Chapter11-32.jpg

需要说明的是,使用日期时间字段值排序时,日期值越小年龄就越大。本例实际是按年龄的降序排列的。

11.3.4 连接不同的数据表(Join语句)

如果希望将数据库中不同表的字段组成一个来自多个表的查询返回集合,需要使用LINQ to SQL提供的Join语句。

【演练11-3】多表查询的实现。数据库StudentInfo中有两个数据表StudentInfo和Stu-dentMark。两个表中的StudentID均为主键,其中存放的数据记录内容如图11-14和图11-15所示。

978-7-111-58440-7-Chapter11-33.jpg

图11-14 StudentInfo表

978-7-111-58440-7-Chapter11-34.jpg

图11-15 StudentMark表

可以看出两个表中的StudentID(学号)字段具有相同的数据,下列代码实现了按照上述两个字段的一对一关系,将StudentInfo表的StudentID、StudentName(姓名)和Student-Mark表的Score(成绩)、DateOfExam(考试时间)字段组合在一起,形成一个新的查询返回集合,图11-16所示为显示在GridView控件中的多表查询结果。

程序设计步骤如下。

(1)生成DataContext类和数据表实体对象

在服务器管理器中配合<Ctrl>键同时选中StudentInfo表和StudentMark表,并将其拖动到O/R设计器中,为两个表创建DataClassesDataContext类和StudentInfo、StudentMark表对象实体,如图11-17所示。

978-7-111-58440-7-Chapter11-35.jpg

图11-16 多表查询结果

978-7-111-58440-7-Chapter11-36.jpg

图11-17 O/R设计器中的两个表

保存文件后在类视图中应看到系统已自动生成了DataClassesContext类、StudentInfo类和StudentMark类。

(2)设计Web页面

向网站中添加一个用于显示查询返回结果的GridView控件GridView1和一个命令按钮控件Button1。设置Button1控件的ID属性为btnQuery,Text属性为“多表查询”。

(3)编写程序代码

在“多表查询”按钮的单击事件中添加以下代码。

978-7-111-58440-7-Chapter11-37.jpg

有下列两点需要说明。

1)本例LINQ to SQL语句中的第一个from语句将StudentInfo表和StudentMark表按照StudentID相等(equals)的关系进行连接生成ResultTable对象。第二个from语句从两个表连接后的ResultTable对象中选择(select)需要的字段,最终存放在Query对象中。

2)DefaultIfEmpty()方法用于返回IEnumerable<T>泛型接口的元素。如果序列为空,则返回一个具有默认值的单一实例集合。也就是说,如果上述代码中不使用该方法,则返回结果中将包含两个表中都存在的记录。

11.3.5 插入新记录

使用LINQ to SQL语句向数据表中插入一条记录的方法十分简单,在创建了DataContext类和数据表实体对象后,只要创建一个数据表对象的实例,并为该实例的各个字段赋值,最后调用数据表对象的InsertOnSubmit()方法,将数据表对象实例添加到表,调用DataContext类对象的SubmitChanges()方法更新数据库即可。

举例如下。

978-7-111-58440-7-Chapter11-38.jpg

11.3.6 修改记录

使用LINQ to SQL技术修改数据库记录的操作与添加新记录十分相似,在创建了DataC-ontext类和数据表实体对象后,首先需要查询到希望修改的记录,然后为查询结果对象中的各个字段赋以新值,最后调用DataContext类对象的SubmitChanges()方法即可。

例如,下面的代码可以实现修改StudentID字段值为200902600004数据表记录的Email字段值为“cqz@163.com”。

DataClassesDataContextdb=new DataClassesDataContext(); //创建Context对象db

//查询StudentID字段值为“200902600004”的记录

StudentInfo StuTab=db.StudentInfo.Single(m=>m.StudentID=="200902600004");

StuTab.Email="cqz@163.com"; //为查询返回结果赋予新值

db.SubmitChanges(); //向数据库提交更新

11.3.7 删除记录

使用LINQ to SQL技术删除数据库记录的操作与更新记录十分相似,在创建了DataCon-text类和数据表实体对象后,首先需要查询到希望修改的记录,然后调用数据表实体对象的DeleteOnSubmit()方法,最后调用DataContext类对象的SubmitChanges()方法即可。

下列语句用于删除StudentInfo表中StudentID为200902600004的一条记录。

DataClassesDataContext db=new DataClassesDataContext(); //创建Context对象db

//查询StudentID字段值为“200902600004”的记录

StudentInfo StuDel=db.StudentInfo.Single(m=>m.StudentID=="200902600004");

db.StudentInfo.DeleteOnSubmit(StuDel); //调用表对象的删除方法

db.SubmitChanges(); //向数据库提交删除操作

11.3.8 使用LINQ to SQL直接执行SQL语句

通过前面的介绍可以看到LINQ to SQL提供了一种全新的操作数据库的方法,但这并不意味着传统的SQL语句彻底失去了存在的必要。很多时候使用SQL语句处理某些问题可能比LINQ to SQL来得更为方便一些。

例如,执行更新或删除操作时LINQ to SQL必须首先要执行查询,然后才能进行更新或删除操作,而且需要批量更新或删除记录时使用LINQ to SQL就非常麻烦。

为此,在LINQ to SQL中提供了一些与传统SQL语句有关的方法,使程序员可以查看LINQ to SQL自动生成的SQL语句内容,直接在LINQ to SQL中调用SQL语句等。

1.GetCommand()方法

GetCommand()方法用于提供有关由LINQ to SQL生成的SQL命令的信息。使用该方法可以帮助程序员了解LINQ to SQL在后台具体的执行情况,这对程序查错而言很有帮助。

例如,下列代码将LINQ to SQL在后台执行SQL语句的相关信息显示到了网页中。

978-7-111-58440-7-Chapter11-39.jpg

978-7-111-58440-7-Chapter11-40.jpg

程序运行结果如图11-18所示。

978-7-111-58440-7-Chapter11-41.jpg

图11-18 使用GetCommand()方法得到SQL数据

2.ExecuteCommand()方法

DataContext类提供的ExecuteCommand()方法可用于直接对数据库执行一个没有返回值的SQL命令。

注意,在书写SQL语句时,表名称和字段名需要用方括号“[]”将其括起来。

例如,下列代码用于将user表中所有记录的userpassword字段值更改为0000(初始化用户密码)。

978-7-111-58440-7-Chapter11-42.jpg

又如,下列代码用于删除user表中Specialty(专业)字段值为“网络技术”的所有记录。

978-7-111-58440-7-Chapter11-43.jpg

3.ExecuteQuery()方法

DataContext类提供的ExecuteQuery()方法用于直接执行一个SQL查询,该方法返回一个IEnumerable<T>类型的泛型集合。

例如,下列代码使用SQL语句对StudentInfo表进行查询,返回表中Specialty(专业)字段值为“软件技术”的所有记录,并将返回的泛型集合作为Grid View控件的数据源将其显示出来。

978-7-111-58440-7-Chapter11-44.jpg

11.4 实训——使用LINQ to SQL操作数据库

11.4.1 实训目的

1)进一步理解创建和使用DataContext类的基本方法。

2)掌握常用的LINQ to SQL语句和方法,掌握通过LINQ to SQL语句或方法实现常规数据库操作的基本步骤。

11.4.2 实训要求

使用LINQ to SQL语句和方法,配合GridView、LinqDataSource等控件,设计一个能对SQLServer数据库StudentDB中StudentInfo表进行查询、添加、修改或删除操作的ASP.NET应用程序。程序启动后显示如图11-19所示的界面。用户在下拉列表框中选择查询关键字的类型(全部、学号、姓名或专业),在文本框中输入查询关键字后,单击“查询”按钮,可得到如图11-20所示的结果。

978-7-111-58440-7-Chapter11-45.jpg

图11-20 按姓名查询记录

在文本框中输入希望修改记录的学号值,单击“修改”按钮,屏幕显示如图11-21所示的界面,用户在修改了记录数据后,单击“提交”按钮可将修改结果提交到数据库,并在GridView控件中立即显示出来。如果用户在没有输入学号的情况下直接单击“修改”按钮,程序将弹出信息框给予出错提示。此外,从图11-21中可以看到修改记录时学号字段是不能修改的,“学号”文本框呈灰色显示。

978-7-111-58440-7-Chapter11-46.jpg

图11-21 修改记录界面

用户单击“添加”按钮时,屏幕显示如图11-22所示的界面,用户在空白文本框中填写了各字段值后,单击“提交”按钮可将新记录添加到数据库中,并立即在GridView中显示出来。

用户通过在下拉列表框中选择删除关键字类型后,在文本框中输入删除关键字并单击“删除”按钮,可将符合条件的记录全部删除。图11-23所示的选择和输入表示的是删除“姓名”字段中包含“张三丰”的所有记录。在删除记录时,如果下拉列表框中选择的是“全部”选项,程序将弹出信息框提示“不要删除全部记录!”。

978-7-111-58440-7-Chapter11-47.jpg

图11-22 添加新记录界面

978-7-111-58440-7-Chapter11-48.jpg

图11-23 删除记录的操作

11.4.3 实训步骤

1.设计Web界面

新建一个ASP.NET空网站,向网站中添加一个Web窗体页Default.aspx。按照图11-24所示向Default.aspx页面中添加一个下拉列表框控件DropDownList1,添加一个文本框控件TextBox1和4个命令按钮控件Button1_Button4;添加一个GridView控件和一个LinqData-Source控件;添加一个Panel控件,并向其中添加一个标签控件Label1,添加6个文本框控件TextBox2_~TextBox7,添加一个命令按钮控件Button2。

978-7-111-58440-7-Chapter11-49.jpg

图11-24 设计Web界面

2.设置对象属性

设置DropDownList1的ID属性为dropSelect,并添加“全部”“学号”“姓名”和“专业”4个选项;设置TextBox1的ID属性为txtKey;设置4个按钮控件的ID属性分别btnSearch、btnEdit、btnAdd和btnDel,设置它们的Text属性分别为“查询”“修改”“添加”和“删除”。

Panel1容器控件中各控件的属性设置如下。

设置Label1的ID属性为lblTip;6个文本框的ID属性分别为txtNo、txtName、txtSex、txtBirthday、txtSpecialty和txtEmail;设置Button2的ID属性为btnOK,Text属性为“提交”。

为了使GridView控件中能显示中文列标题及适当的日期格式,需要切换到Default.aspx页面的源视图,按以下所示添加CSS样式设置和修改GridView控件的描述代码。

设置CSS样式,代码如下。

978-7-111-58440-7-Chapter11-50.jpg

修改GridView代码,代码如下。

978-7-111-58440-7-Chapter11-51.jpg

3.创建DataContext类和配置LinqDataSource

在解决方案资源管理器中右击网站名称,在弹出的快捷菜单中选择“添加”→“添加新项”命令,在弹出的对话框中选择“LINQ to SQL类”选项后单击“添加”按钮。从服务器资源管理器中将StudentInfo表拖放到O/R设计器的左窗口中,单击工具栏中的“保存全部”按钮,完成DataContext类的创建。使用配置完成的DataContext类配置LinqDataSource1。

4.编写程序代码

1)页面载入时执行的事件代码如下。

978-7-111-58440-7-Chapter11-52.jpg

2)“查询”按钮被单击时执行的事件代码如下。

978-7-111-58440-7-Chapter11-53.jpg

978-7-111-58440-7-Chapter11-54.jpg

3)“修改”按钮被单击时执行的事件代码如下。

978-7-111-58440-7-Chapter11-55.jpg

4)“提交”按钮被单击时执行的事件代码如下。

978-7-111-58440-7-Chapter11-56.jpg

978-7-111-58440-7-Chapter11-57.jpg

5)“添加”按钮被单击时执行的事件代码如下。

978-7-111-58440-7-Chapter11-58.jpg

6)“删除”按钮被单击时执行的事件代码如下。

978-7-111-58440-7-Chapter11-59.jpg

相关教程

共有条评论 网友评论

验证码: 看不清楚?