毋庸置疑,在数据库访问方面,SQL是名符其实的标准。但是,SQL却不能直接操作实体。于是,在实体与数据库访问之间,就出现了一道鸿沟。Entity SQL(以下简称eSQL)的出现,即用于填补这两者之间的不匹配问题。通过本文,我们将了解到eSQL的一般使用方法以及两套使用的接口。
一、要完成本文中的实例,您需要作如下准备:
- 将Visual Studio 2008及.NET Framework 3.5升级到SP1。点击转到升级地址。
- 安装SQL SERVER 2005,VS 2008中自带的EXPRESS版的SQL SERVER应该也可以用。
- 下载并附加数据库:点击下载DemoDbV2。
- 创建一个VB Console Application,并且取一个合适的名字(例如:EntitySQL之类的)。注意,目标Framework要设置成3.5版。
当前数据库Notebook表中数据如下:
图1 |
二、为什么要使用eSQL?
eSQL自出生之日起,日子就不怎么好过。为什么这么说?大家针对数据库访问,习惯性的想到SQL;而在EF正式发布前,大家已经对LINQ有所了解,因此,针对实体的访问,大家首先想到的应该是LinQ。那么,微软为什么还要推出eSQL?它相对于SQL、LinQ有什么优势?
相对于SQL,eSQL提供了对实体的很好的支持——这是SQL所不具备的(历史原因 ^_^)。SQL查询出来的是行,eSQL,则可以直接查询出实体集。eSQL直接支持EDM中的类型,而SQL不支持(废话,有SQL的时候,EDM还没有出世呢)……
相对于自己的哥哥——LinQ,eSQL显得更为灵活。由于eSQL的查询语句是个字符串,因此,其十分易于处理。举个简单的例子,如果我要写一个方法,传入排序的属性名称,返回一个按照此属性排序好的实体集,要用LinQ实现,恐怕有点麻烦,因为,其ORDER BY后面,需要跟一个实体类的属性;然而,在eSQL里,这简单是轻而易举的事,只要写上一个eSQL语句,把排序位置留为{0},然后进行字符串替换,这一功能就完成了——好像比较难说明白,没有关系,后面的示例代码里有相关的部分。
总之,一句话,eSQL是个好东东——因为它是本文介绍的主角^_^。至于到底是不是那么一回事儿,大家可以试一下本文的示例,然后,根据自己的理解来酌情运用。
三、eSQL的使用方法
EF为eSQL提供了两套接口:Entity Command接口和ObjectQuery接口。让我们首先来了解一下这两套接口的使用模式:
-
Entity Command接口:
'Using EntityCommand Interface Private Sub QueryESql1() Using eConn As New EntityConnection(ConnString) Dim myQuery = "{0,1,2,3}" Using cmd As New EntityCommand(myQuery, eConn) eConn.Open() Using reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess) While (reader.Read()) Console.WriteLine(reader.GetValue(0)) End While End Using End Using End Using End Sub |
首先,通过预先配置好的连接字符串,创建一个EntityConnection类型的连接eConn;
然后,定义查询语句;
第三步,通过连接和查询语句,创建一个EntityCommand的对象cmd;
第四步,打开连接,读取数据。
这一接口形式,更接近于传统的ADO.NET的调用形式。
-
ObjectQuery接口:
'Using ObjectQuery(Of T) interface Private Sub QueryESql2() Using objContext As New ObjectContext(ConnString) Dim myQuery = "NotebookEntities.Notebook" objContext.Connection.Open() For Each aLaptop As Notebook In New ObjectQuery(Of Notebook)(myQuery, objContext) Console.WriteLine(aLaptop.Brand & " " & aLaptop.Type) Next End Using End Sub |
第一步,通过连接字符串,创建一个ObjectContext对象objContext;
第二步,字义查询语句;
第三步,打开连接,查询数据。
这个形式,比较充分的利用了eSQL对实体类形的支持。
四、实例
1. 从数据库获取全部的笔记本电脑数据,显示其品牌、型号。
Entity Command接口实现方法:
'Using EntityCommand Interface Private Sub QueryESql1() Using eConn As New EntityConnection(ConnString) Dim myQuery = "SELECT n.Brand, n.Type FROM NotebookEntities.Notebook as n" Using cmd As New EntityCommand(myQuery, eConn) eConn.Open() Using reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess) While (reader.Read()) Console.WriteLine(reader.GetValue(0) & " " & reader.GetValue(1)) End While End Using End Using End Using End Sub |
我们通过写一个eSQL语句,从NotebookEntities实体容器的Notebook实体集中,把所有的实体一行行取出,并通过DbDataReader实现的对象将其输出。运行结果如下:
图2 |
而ObjectQuery接口则更加直接:
'Using ObjectQuery(Of T) interface Private Sub QueryESql2() Using objContext As New ObjectContext(ConnString) Dim myQuery = "NotebookEntities.Notebook" objContext.Connection.Open() For Each aLaptop As Notebook In New ObjectQuery(Of Notebook)(myQuery, objContext) Console.WriteLine(aLaptop.Brand & " " & aLaptop.Type) Next End Using End Sub |
通过一个For Each循环,对ObjectQuery(Of Notebook)返回的实体集进行遍历,每一个实体的Brand和Type属性输出到屏幕上。输出结果与图2相同。
2. SELECT VALUE
在上面两个查询中,通过eSQL返回出来的,仍然是一个ROW对象。这就是说,即使我们写下面这样一条eSQL语句:
SELECT n.Brand FROM NotebookEntities.Notebook AS n |
输出结果时,我们仍然需要写上reader.GetValue(0)来处理。
然而,很多时候,我们需要仅对一个值进行操作(这个值可以是简单的一个整数或者是一个复杂对象、一个实体……)。这时,eSQL引入了新关键字VALUE。我们来看看如何选出一个实体值:
'Select & Select VALUE Private Sub QueryESql3() Using eConn As New EntityConnection(ConnString) Using objContext As New ObjectContext(eConn) Dim myQuery = "SELECT VALUE n FROM NotebookEntities.Notebook AS n" objContext.Connection.Open() For Each aLaptop As Notebook In New ObjectQuery(Of Notebook)(myQuery, objContext) Console.WriteLine(aLaptop.Brand & " " & aLaptop.Type) Next End Using End Using End Sub |
通过添加一个简单的关键字VALUE,通过eSQL返回出来的,就是一个值而非一个ROW了。
3.内建的分页支持
自定义分页一直是一个企业应用中常用的功能,同时也是一个比较费时又容易出问题的地方。现在,eSQL内建了对自定义分页的支持。使用方法非常简单,只需要两个参数:SKIP、LIMIT。
其中,SKIP表示需要跳过的行数。例如,SKIP 2则从第三行进行输出,在分页中可以作为rowStartIndex来使用;LIMIT则表示需要输出的最大行数,在分页中可以作为pageSize来使用。我们来看一个例子:
'Build in paging ''' <summary> ''' Query data with build in paging ''' </summary> ''' <param name="startIndex">Start entity index start from 0</param> ''' <param name="pageSize"></param> ''' <remarks></remarks> Private Sub QueryESql4(Optional ByVal startIndex As Integer = 0, Optional ByVal pageSize As Integer = 10) Using eConn As New EntityConnection(ConnString) Using objContext As New ObjectContext(eConn) Dim myQuery = "SELECT VALUE n FROM NotebookEntities.Notebook AS n ORDER BY n.Brand SKIP {0} LIMIT {1}" myQuery = String.Format(myQuery, startIndex, pageSize) For Each aLaptop In New ObjectQuery(Of Notebook)(myQuery, objContext) Console.WriteLine(aLaptop.Brand & " " & aLaptop.Type) Next End Using End Using End Sub |
在这段代码时,我们通过把startIndex和pageSize作为参数传入,替换查询语句中SKIP和LIMIT后面的值,来达到分页输出的目的。需要注意一下的是,SKIP和LIMIT,需要依赖ORDER BY。因此,必须针对某一属性进行排序后,方可使用SKIP和LIMIT来进行分页。当传入参数(2,2)时,输出结果如下:
图3 |
五、示例代码下载
点击下载。
Little knowledge is dangerous.