Entity SQL是一种"仿SQL"的语言,因此,它在基本遵守SFWGHO的基础上,稍微加以扩展,形成了一套较SQL来得强大的查询语句。本篇将介绍Entity SQL的基本查询方法,展现它与传统SQL不同的地方。本篇会使用到一些Entity SQL中特有的类型,像"行"、"集合"之类的。如果您对Entity SQL中的这些概念不是很熟悉,您可以参考我的另一篇随笔。
首先,题外一句,SWFGHO是什么?SFWGHO是:SELECT-FROM-WHERE-GROUP BY-HAVING-ORDER BY的首字母缩写,也是SQL查询语句的最基本构成方法。
好了,进入主题。Entity SQL提供了一种最简单的查询方法——表达式。一个表达式即一个查询语句。
举例说明,以下表达式,均可以看作是Entity SQL的查询语句(每行一个):
1 1*2%3 MAX({1,3,4}) CASE WHEN MIN(MULTISET(-3,1,9))<0 THEN -100 ELSE 100 END SUBSTRING('Hello',2,3) |
呵呵,一个简单的常数"1"就是一个简单的查询语句,太变态了……但你的确可以用它查询出结果来,不信,可以把它放到eSqlBlast里试试。
当表达式与SFWGHO相结合,就形成了看上去比较正常的Entity SQL查询表达式了,例如:
SELECT N FROM NbWhEntities.Notebook AS N |
即可得到查询结果:
下面这个查询语句跟传统的SQL就更像了:
SELECT N.Brand, N.Type FROM NbWhEntities.Notebook AS N Order by N.Brand |
得到结果:
大家尽可以把它们当作传统的SQL来写。但是有两点需要注意:
1. Entity SQL不支持SELECT * 操作,也就是说,必须要SELECT列或者实体的别名。
2. 在Entity SQL中,建议显式的使用AS关键字。虽然在有些情况下,Entity SQL可以自动推断别名,但有时候,就会出错。因此,显式使用AS来声明别名有助于减少错误。
另外,在Entity SQL中,SELECT又可细分为SELECT ROW和SELECT VALUE两类。如果直接写SELECT,那么, Entity SQL将永远返回行对象集合——即使指定了只返回某一列属性。因此,如果这样写,我们会用类似以下的代码来访问数据:
Imports System.Data.EntityClient Imports System.Data.Objects Imports System.Configuration Imports System.Data Imports System.Data.Common … Public Sub SelectAndSelectValue() Dim connString = ConfigurationManager.ConnectionStrings("NbWhEntities").ToString() Using objContext As New ObjectContext(connString) Dim myQuery = "SELECT N.Brand FROM NbWhEntities.Notebook AS N" objContext.Connection.Open() For Each rec As DbDataRecord In New ObjectQuery(Of DbDataRecord)(myQuery, objContext) Console.WriteLine(rec("Brand")) Next End Using End Sub |
大家注意到,这里,我们取得的是整个行的"Brand"列里的值——实际上,这些行也只有这一个列。如果我们使用SELECT VALUE,就可以直接返回这个值,而不使用行来进行返回。例如:
'SELECT VALUE Using objContext As New ObjectContext(connString) Dim myQuery = "SELECT VALUE N.Brand FROM NbWhEntities.Notebook AS N" objContext.Connection.Open() For Each s As String In New ObjectQuery(Of String)(myQuery, objContext) Console.WriteLine(s) Next End Using |
这段代码运行结果与上一例相同,但是,我们直接查询出了string对象集,而不再是行集。再进一步,我们可以直接查询出实体:
'SELECT VALUE - Entity Using objContext As New ObjectContext(connString) Dim myQuery = "SELECT VALUE N FROM NbWhEntities.Notebook AS N" objContext.Connection.Open() For Each n As Notebook In New ObjectQuery(Of Notebook)(myQuery, objContext) Console.WriteLine(n.Brand) Next End Using |
呵呵,这恐怕是简单查询里的最高形式了,直接查询出实体集,然后,输出这个实体集中的一个属性。
由于在实体数据模型中,引入了继承的概念,因此,Entity SQL也引入了三个新的关键字来对这一特性加以支持,它们是:OFTYPE、IS OF和TREAT。
让我们回顾一下《ADO.NET Entity Framework 试水——映射》一文中提到的继承关系:
如果大家一直关注Entity Framework试水系列,一定对第五节中提到的继承关系有所记忆。我们把笔记本分为用于出售和不出售的两类,出售的需要提供价格和代理商属性。那么,使用OFTYPE,我们可以方便把这两类笔记本区分出来。
OFTYPE的语法:OFTPYE(entitySet, nominalTypeInstance)
其中,entitySet为实体集,而nominalTypeInstance是其本身类或者其继承类。它约束返回的对象的类型。例如:
OFTYPE(NbWhEntities.Notebook, NbWhModel.SalesNotebook) |
它会把所有的SalesNotebook返回出来。通过TREAT 和IS OF可以达到同样的效果:
SELECT VALUE TREAT(N AS NbWhModel.SalesNotebook) FROM NbWhEntities.Notebook AS N WHERE N IS OF(NbWhModel.SalesNotebook) |
在这里,我们把Notebook中的实体查询出来,把它当作NbWhModel.SalesNotebook来对待;同时,需要一个查询条件,即它是NbWhModel.SalesNotebook。
小结:
本篇,我们看到了Entity SQL的最简单形式——表达式;SFWGHO形式,以及SELECT ROW和SELECT VALUE的区别。最后,我们看到了三个两组新关键字:OFTYPE、TREAT以及IS OF。
Little knowledge is dangerous.