[C#]Entity Framework之Entity SQL(三) 1:N关系型数据的查询

SQL中,要在一个一对多关系中查询数据,不免要使用JOIN关键字。在Entity Framework中,由于引入了Navigation属性的概念,我们可以通过Navigation属性,直接在多个实体之间进行查询而不必过多的关心 主键、外键约束……本文将通过一个Demo,来展现如何通过Entity SQL,方便在1对多关系的实体间进行查询。

进入正题之前,让我们来看一下当前数据库的情形,以及我们将要完成的任务。

本文主要将涉及到两个表的查询:Warehouse和Notebook。Warehouse中有三个仓库的记录;Notebook中有6台笔记本的记录;每个笔记本至多属于一个仓库,每个仓库可以存储0个或者多个笔记本。于是,在笔记本与仓库之间,构成N:1的关系。

本文将要进行两组查询,分别给出SQL查询与Entity SQL的查询语句,以方便比较。第一组查询,以1端为条件,查询多端结果;第二组查询,以多端为条件,反过来查询1端的结果。

实例1 查询出全部存放在仓库的城市为"SH"的笔记本——N到1查询

SQL实现如下:

Select n.* FROM Notebook as n

INNER JOIN Warehouse as w

ON n.WarehouseId=w.Id

Where w.City='SH'

我们把Notebook与Warehouse通过仓库ID内联以后,以1端,即Warehouse端作为条件,查询出全部在上海的笔记本。下面的Entity SQL语句,可以达到相同的效果:

Select VALUE n FROM DemoDbEntities.Notebook AS n

Where n.Warehouse.City = 'SH'

我们通过Notebook的Navigation属性——Warehouse,访问到对应的仓库所在的城市,进而来过滤出附合条件的笔记本。我们来看一个ObjectQuery的实现接口:

private static void RelNav1()

{

     string query = "Select VALUE n FROM DemoDbEntities.Notebook AS n"

                    + " Where n.Warehouse.City = 'SH'";

     using (ObjectContext oc = new ObjectContext(ConnectionString))

     {

          oc.Connection.Open();

          foreach(Notebook notebook in new ObjectQuery<Notebook>(query,oc))

          {

               Console.WriteLine("{0} {1}", notebook.Brand, notebook.Type);

          }

     }

}

其中,ConnectionString是连接字符串。这一查询模式我们在前文已经介绍过,这里不再赘述了。

实例2 查询出全部的存有品牌为"ThinkPad"或者"Lenovo"的仓库——1到N查询

SQL实现如下:

Select DISTINCT w.* FROM Notebook AS n

INNER JOIN Warehouse AS w

ON n.WarehouseId = w.Id

Where n.Brand='ThinkPad' OR n.Brand='Lenovo'

在SQL中实现的思路与实例1一样,都是把Notebook和Warehouse作内连接,只不过,把Where条件修改为n的品牌;而Select的是w.*。

Entity SQL在作1到N的查询时,稍有一点点不大一样,不过,仍然十分方便:

Select VALUE DISTINCT w FROM DemoDbEntities.Warehouse AS w, w.Notebook as nbs

Where nbs.Brand = 'ThinkPad' OR nbs.Brand='Lenovo'

我 们首先选出所有Warehouse,记为w,然后,把w.Notebook记为nbs,然后,设置查询条件nbs.Brand为"ThinkPad"或 者"Lenovo"。这里有一个顺序,在FROM子句中,允许访问在先前已经定义的别名。这就是为什么我们在定义了w之后,可以马上访问 w.Notebook。

ObjectQuery实现接口与实例1中的接口一致,唯一差别在于修改了查询串:

private static void RelNav2()

{

     string query =

          "Select VALUE DISTINCT w FROM DemoDbEntities.Warehouse AS w, w.Notebook as nbs " +

          " Where nbs.Brand = 'ThinkPad' or nbs.Brand='Lenovo'";

     using (ObjectContext oc = new ObjectContext(ConnectionString))

     {

          oc.Connection.Open();

          foreach (Warehouse w in new ObjectQuery<Warehouse>(query, oc))

          {

               Console.WriteLine("{0} {1}", w.Name, w.City);

          }

     }

}

 

我们看到,通过Entity SQL,我们需要关心的,不再是关系模型中表与表之间的关系、主键、外键、连接,而只要处理好Navigation属性即可。只要建立了Navigation属性,哪怕不存在外键约束,一样可以在多个实体集之间进行联合查询。

另外,需要说明的是,Where子句里,要求提供的是集合,而不是单个值。举例说明,当存在一个如下的查询语句:

Select VALUE DISTINCT w FROM DemoDbEntities.Notebook AS n, n.Warehouse as w

Where w.City='SH'

由于Notebook与Warehouse是多对一的关系,因此,n.Warehouse,即w必定是1,而不是集合。然后,很不凑巧,w.City又出现在了Where子句里。因此,会得到一个与下述类似的错误信息:

The specified expression must be of CollectionType.

对于以上的语句,第一,可以修改成实例1中所述的形式。另外,还有一个快速的Workaround,虽然不推荐使用,但这有利于大家理解Where子句中必须提供集合:

Select VALUE DISTINCT w FROM DemoDbEntities.Notebook AS n, {n.Warehouse} as w

Where w.City='SH'

我们把{n.Warehouse}记为w,w便成了一个集合,便可以出现在Where子句中了。

小结:

本文简单的介绍了Entity SQL在一对多查询中的应用;我们举例说明了1对多以及多对1的关系场景,并且了解到,在Entity SQL中,不再需要过多的考虑关系模型中的主外键约束情况,而更多的使用Navigation属性。

Demo下载

1. 数据库文件

2. 源代码(C#版)

Little knowledge is dangerous.

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏