Evil 域

当Evil遇上先知

导航

Entity Framework之Entity SQL(二) 基本查询

Posted on 2008-10-08 21:44  Saar  阅读(8246)  评论(4编辑  收藏  举报

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。