深入浅出学Linq:Linq to SQL How do I(2)

本篇是Linq to SQL How do I的第二篇,难度系数100,定位为进阶级。



引用:

内容

l 对象之间的关系



对象之间的关系

既然是对象-关系映射,各个表之间肯定不是独立存在的(如果都是独立存在的,也没有必要用关系数据库了),那么就必然涉及到几个表之间的联合了。

Linq to SQL和SQL语句一样,支持两种方式的联合:

1.      利用where子句,对两个表进行查找

2.      使用join子句

我们还是用例子来说明吧,现在要对blogs和posts进行查询,传入一篇文章的id的时候,找出这篇文章相关信息的同时还要找出这篇文章属于哪个博客,接着上篇的例子,我们首先得给Blog类加上映射:


博客类映射(Blog)

Code


首先获取Post和Blog的Table<TEntity>的对象,然后施加操作:

Code


下面是Linq to SQL为我们生成的SQL语句,从上面可以看出来是用where做联结的条件来进行的,这种联结的方式是不被推荐的,存在于ANSI-82 SQL的标准中

 附件: 您所在的用户组无法下载或查看附件
推荐的方式是使用join子句:

Code


生成的SQL语句是:

 附件: 您所在的用户组无法下载或查看附件
大家看到,Linq to SQL使用inner join子句。
但是Linq to SQL在使用join的时候并不是像SQL那样宽松,把上面的SQL语句贴下来:

Code


在SQL语句里,ON子句的[t0].[blogid] = [t1].[BlogId]左右次序是没有关系的:[t0].[blogid] = [t1].[BlogId]或[t1].[BlogId] = [t0].[blogid]的结果是一样的,但是在Linq to SQL里并不是如此,她要求查询的对象和ON子句里面的东西的位置是一一对应的:

 附件: 您所在的用户组无法下载或查看附件
 

如上图,用框子框起来的四部分,橙黄色的两个,蓝色的两个,位置都是一一对应的,blog排在第一位,那么blog.Id就要排在on的第三位,1,3和2,4这种对应关系。这又是为什么呢?因为这种查询表达式最后要被转换成方法调用,而扩展方法Join的原型是:

Code


大家看到没,第一个参数和第三个参数都是outer相关的,第二个参数和第四个参数都是inner相关的,最后一个是on条件时的条件运算符,如:equals。将上面的方法原型和上面那张图对应:blogs就是这里的outer,而blog.Id对应着这里的outerKeySelector,posts就是这里的inner,post.BlogId对应着这里的innerKeySelector,equals就是这里的resultSelector。实际上,如果你使用VisualStudio2008编写代码的时候,如果不按照这个顺序敲入代码,vs是不会给你智能感知的。
大家也许发现上面的join生成的SQL语句只有inner join(inner join也称之为等值连接,只返回两个表联结字段相等的行),在我们这个需求里,这样使用是合理的:查找一篇文章,如果该文章对应的博客不存在的话,这篇文章也不应该显示。但是,如果我们期望使用outer join咋办呢?Linq为我们提供了一个DefaultIfEmpty()的扩展方法:

Code


这样生成的SQL语句就是这样的了:

 附件: 您所在的用户组无法下载或查看附件
看到上面说了那么多,也许有人会问:一般的ORM框架都能在对象之间建立关系来反映数据库之间的关系,而操作的时候这种关联是自动的,难道Linq to SQL必须让程序员手动的使用这种join的方式来处理对象之间的关系么?答案是否定的。


一对多关系(One-to-Many)

在上面的映射中,Blog还有一个属性:Posts,我们并没有做什么处理,实际上这个应该是根据Blog的Id属性关联到Post的BlogId属性,进行关联的。

为此我们要修改一下这个Blog的映射:

Code


使用Association建立映射关系,她有一个OtherKey属性,该属性指定为被关联的那个对象中做连接的那个属性(外键)(这里被关联的就是Post类,做连接的那个属性就是BlogId,她也是posts表的外键),还要注意的是,我们要把原来使用的IList<Post>换成EntitySet<Post>,EntitySet<TEntity>是Linq新提供的一个类,在System.Data.Linq命名空间下。
下面来看看例子:

Code


我们只要对blog进行查询就ok了,和她关联的Post自动的会映射过来的。

上面的例子只表明了在Blog类里,如何关联到该博客的所有Post,如果我在Post里想关联到该Post属于哪个博客呢?

在Post类里添加:

Code


这样就ok了,你查一个Post的时候会自动的把其所属的博客也给弄出来哦。而且这个EntityRef还是支持延迟加载的。



多对多的关系(many-to-many)

Linq to SQL默认是不支持多对多的关系的,所以也没有针对多对多关系的Attribute和Query,不过网上有很多多对多关系的解决方案,在这里我就不做介绍了,我给个连接:

http://blogs.msdn.com/mitsu/arch ... ng-linq-to-sql.aspx

这位大哥的方案是一个通用的,你可以下载他的代码应用到你的项目当中,有时间我会把这个翻译一下。



一对一的关系(one-to-one)

一对一的关系Linq to SQL是支持的,你只要给关系的两边都加上EntitySet<TEntity>属性就可以了,下面用实例做个演示:

在我们的实例中,每个用户对应着一个博客,每个博客也只对应着一个用户,这是个一对一的关系:

用户类映射(User)

Code


Blog类前面已经出现过,我们就不列出全部代码,将Blog类修改如下:

Code


就是添加一个EntitySet<User> User的属性而已。

看看操作:

 附件: 您所在的用户组无法下载或查看附件

通过查询结果可以看出,他们之间的关系建立了。



后记

本来这一篇我准备了好几个内容,但是在上篇评论里,有人说我的一篇太长了,确实,如果太长了,没有多少人能有耐心看下去,而且看的时间太长对眼睛也不好,在办公室里也不好意思老顶着屏幕看博客吧,boss看了也不好啊,所以这篇就光说一个关联了,那看来这个How do I原计划的三篇是不能完成了。其实文章有点长,看起来应该很快,没有什么难度的内容,而且我是以讲话的风格写的,本系列的内容我的计划是把Linq讲的透透彻彻的,从表面上如何使用,到后面是怎么实现的都说一遍,所以每一篇都是整个系列的一个元组。


(文/yuyijq  出处/博客园)

 感谢原创者的辛勤劳动,希望对您有所帮助,转载请注明原出处。
 您可能对 [Linq] 的这些文章也感兴趣:

LINQ体验(16)——LINQ to SQL语句之DataContext
深入浅出学Linq-Linq to SQL DataContext的初始化
LINQ To SQL && Lambda 使用方法小结
LINQ体验(2)——C# 3.0新语言特性和改进(上篇)
在LINQ to SQL中使用Translate方法以及修改查询用SQL
扩展LINQ to SQL以支持批量删除
Linq系列:基础与本质(Part I)
使用linq to xml 快速创建RSS
Presentation: Beth Massi on Conquering XML with LINQ in VB9
LINQ to SQL活学活用(4):监视你的一举一动