SharePoint 2010中几种数据访问方式的原理和优劣

今天去客户那边的时候,正好对方问起几种数据访问方式的优劣,索性在此总结一下。本篇博客中不涉及到什么新的技术,也没有代码示例,只是从原理上解释一下各种数据访问方式,从而对比出这几种方式之间的优劣。

在SharePoint 2010中,基本上有如下几种数据访问方式:

  • 服务器端对象模型
  • LINQ to SharePoint
  • Web Service
  • 客户端对象模型
  • ADO.NET Data Service (REST协议)
  • ADO.NET Data Service (强类型)

当然,还有比如通过WebDav和RPC这种用的人很少(SharePoint内部、以及SPD里面倒是有不少地方在用),而且功能也比较局限的访问方式就暂且不提了。还有就是PowerShell这种使用场景比较窄的方式,也暂且不提了。

1、服务器端对象模型(Server Object Model)

这个是应用的最为广泛的数据访问方式,其功能上也是最完整的。实际上,SharePoint几乎所有自己的控件、Web部件、页面都是通过这一套对象模型写出来的(当然,可能用到了其中的一些internal的方法或者属性)。之前我去培训的时候,在介绍SharePoint开发概述时总说的一句话就是:在SharePoint默认页面里面通过点击鼠标键盘能完成的操作,绝大多数情况下使用服务器端对象模型都能完成;而且也有很多操作,你通过SharePoint内置的UI实现不了,但是通过Server OM也可以实现(比如跨网站的查阅项、多列表关联查询、视图中的若干筛选、排序条件等等等等,数不胜数)。

服务器端对象模型顾名思义,是只能运行在服务器端的(换句话说,只能运行在装了SharePoint的机器上,而且一般情况下只能访问当前这个场的资源),归根结底是从Web前端服务器(WFE)直接访问后台数据库的(对于那些Service Application的API而言,是通过前端的Proxy连接到应用程序服务器的WCF接口的,在后面的介绍中,我们暂且忽略这种场景)。如下图所示:

image001

因为WFE和DB之间有良好的带宽保障,因此在做一些数据访问和操作的时候,可能会造成多次数据往返,而且往返的内容可能比你想象的要多(因此在所有的SharePoint部署场景中,强烈建议把前端和数据库安排在同一个局域网的同一个网段内,充分保证其带宽)

此外,在SharePoint数据库中的所有数据操作都是通过存储过程来完成的,因此,除非你100%地确定后果,千万不要直接去修改SharePoint数据库里面的数据。

2、LINQ to SharePoint

SharePoint本身的那些SPxxxxCollection类中,并不是所有的都实现了IEnumerable<T>的接口,因此传统的LINQ to Object并不能用在大多数常用的对象上。这里面的LINQ to SharePoint特指针对SharePoint列表条目的查询。(客户端对象模型有自己的类似LINQ to Object的能力,本文不讨论这一点)

LINQ to SharePoint在2007的时候是一个CodePlex上面的开源项目(第三方的),据说后来这个作者就被挖到微软去了(坊间八卦,真假不明)。

在SharePoint 2010中,LINQ to SharePoint需要开发人员通过SPMetal.exe这个命令行工具生成一个实体的DataContext类(或者你足够熟悉这一套框架的话,自己写也行)。LINQ在做查询的时候,会把大部分的查询翻译成CAML语句,然后交给传统的SPQuery去执行,再把返回结果处理成实体类对象,如下图所示:

image002

SPQuery是个服务器端API,所以LINQ to SharePoint也是仅能够运行在服务器端(那个SPMetal工具倒是可以通过客户端访问),严格意义上说,这个应该算是服务器端对象模型的一部份。

LINQ to SharePoint的优势有三个:第一、实体类,在编程的时候更直观;第二、在处理复杂查询,尤其是多列表联合查询的时候,编写查询条件更容易和直观;第三、LINQ to SharePoint不仅支持数据的查询,同时也支持数据的添加、修改和删除,并且可以像强类型数据集那样,通过SaveChanges方法,把所有的修改一次性地提交到网站中。

但是LINQ to SharePoint本身也会在一定程度上造成性能损失,主要原因有二:第一、把数据转换成实体类,在数据量很大的时候,这个开销是难以忽视的;第二、把查询转换成CAML查询,这本来是个很小的开销,但是SharePoint 2010在处理有些LINQ语句(比如FirstOrDefault这种),不能“正确”地处理成最优的CAML查询,可能会把LINQ to SharePoint退化成LINQ to Object,也就是先返回并实体化列表中的所有数据,然后再在内存中做查询,从而造成极大的性能问题。

3、Web Service

Web Service是SharePoint中非常传统的一种数据访问方式,从2003的时候就有(2001我没有接触过,不确定有没有,欢迎用过2001的人补充),而且一直以来变化都不大(美其名曰向前兼容)。

这些Web Service接口都是在_vti_bin这个虚拟目录(物理目录在14\ISAPI)中的若干个asmx,和客户端连接的时候走的是标准的SOAP协议,也就是说在传递过程中用的都是Xml,当然在其后台,执行的逻辑依然是通过服务器端API去完成的,如下图所示:

image003

上图中需要注意的一个特点,就是在每一次执行Web Service中某个方法的时候,都和服务器有数据交互,这一点和后面提到的某几种方式有很大区别。

SharePoint 2010中,对于大多数常见操作,多多少少都会有Web Service接口,不仅包括最常用的网站、列表、列表数据、工作流的操作(虽然某些操作在处理起来的时候会比较别扭,典型的一个例子就是通过Copy.asmx实现文件上载;此外不建议使用Web Service来设置权限,由于历史原因造成了写法非常不标准),也包括了在标准版或企业版中才有的对于用户配置文件、企业搜索、Excel Service等服务的常规操作,操作的涵盖面还是比较广的。

但是Web Service在编写的过程中,有如下两个问题:

第一、所有操作的处理结果都是Xml格式,也就是说,如果需要获取数据的话,需要你自己去解析这些Xml,而且涉及到列表字段的时候,基本上都要使用内部名称,对于稍微复杂一些的操作(比如列表查询等),在传递参数的时候,也是要传递一个XmlNode类型的参数,而不是一个简单的string;

第二、由于Web Service在返回的时候会返回Xml格式,而且很难去控制要返回哪些属性(比如在获取列表的时候,可能会把列表里面的各种架构、属性都一次性返回),如果程序处理不当,很容易造成返回结果非常庞大,这直接就带来了两个后果:(1)如果客户端和服务器端之间的网络带宽有限的话,可能会对操作的速度有所影响;(2)很容易造成返回超时或者数据过大的错误。我们在一些项目里面就曾经遇到过类似的问题,比如一次性获取上千条列表条目的时候,就会出现异常,我们不得不通过分页的方式把数据拆分成多次获取,但是这样一来又无可避免地增加了程序的复杂度。

4、客户端对象模型

客户端对象模型是SharePoint 2010新增的一个开发特性(当然,在2007的时候,也有一些第三方的手段,比如我写的这个:SharePoint JavaScript Lib),根据使用环境的不同,可以分为.NET客户端对象模型、Silverlight客户端对象模型、JavaScript客户端对象模型。后面两种在SharePoint 2010中,依然必须把silverlight或者js脚本放在SharePoint网站里面才能正常运行(但是实际的运行环境是发生在客户端的浏览器进程里面,所以也算是客户端访问),所以这里面我们就只以.NET客户端对象模型来进行说明。

几种不同方式的客户端对象模型都有自己的运行时环境,但是他们都有统一的数据访问层,那就是位于_vti_bin下(没错,跟Web Service在一个目录里)的Client.svc这个WCF接口,其具体的执行原理如下:

image004

从图中我们可以看到,在执行客户端API的时候,并不会和服务器端发生交互,直到当我们执行了ExecuteQuery这个方法(或者它的异步版本ExecuteQueryAsync)的时候,客户端运行时环境会把之前所有的操作序列“翻译”成一段Xml,发送到服务器端的WCF接口,然后服务器端通过服务器端对象模型依次执行其中的操作,然后把我们所需的结果通过JSON的格式返回给客户端运行时,再由客户端运行时把这个JSON翻译成相应的对象。——这是客户端对象模型访问时候的一大特点。

它的另一个特点,在于我们在获取返回数据的时候,需要“显式”地指定我们所需的结果(通过Load方法),甚至可以通过Load方法的一些重载,去指定我们所需对象的属性、字段(比如只获取列表的标题属性、只获取列表条目的某几个字段值等等)。而服务器端在返回结果给客户端的时候,会根据我们事先声明的返回需要,只传递那些我们需要的值回来。

通过上述两个特点,我们就可以看出,客户端对象模型的一个优势,就在于它可以把客户端和服务器端数据传递的次数和大小都降至最低,从而在带宽难以保证的情况下获得较好的执行效率,也可以一次性返回更多的内容回来。

不过客户端对象模型的功能也是有局限的,在SharePoint 2010中,客户端对象模型只包含了SharePoint Foundation的功能,包括网站、列表结构、列表数据、权限、用户、文件、文件夹等等。对于标准版或者企业版中提供的一些功能,目前在客户端对象模型中没有提供相应的接口。

5、ADO.NET Data Service(REST协议)

这依然是SharePoint 2010新增的一个接口,位于_vti_bin目录(好吧,它们都在一起)中的listdata.svc。

REST协议的一个特点,就是可以把我们需要的操作都浓缩在一个URL中(比如通过:_vti_bin/listdata.svc/Employee(3)就可以获取到Employee这个列表中ID为3的那个条目的信息,当然也可以通过一些特殊的写法实现简单的查询、排序功能),并可以通过GET、POST、PUT、DELETE、MERGE这几种HTTP访问方式,来实现列表数据的增、删、查、改。

通过REST协议访问数据的原理如下图所示:

image005

通过这种方式访问的时候,客户端使用JSON的格式把需要的数据通过某种HTTP方法发送至包含listdata.svc的Url地址上(如果是Get方法的话,就没有发送的数据),然后返回数据的时候,可以返回Xml格式(Atom协议),也可以返回JSON格式(如果不特别声明的话,默认使用Atom协议,也就是Xml格式)。

和客户端对象模型相同的是,我们通过Url,可以定义所需要返回的那些字段值,从而减少客户端和服务器端的数据传递大小。

但是通过listdata这个接口名字也可以看出来,这个接口只提供列表数据的访问能力。(在Excel Service中,也提供了类似的REST协议)

[注]如果需要在SharePoint 2010中使用ADO.NET Data Service,需要手动安装.Net Framework 3.5 SP1 ADO.NET Data Service Update,这个更新包是不会包含在SharePoint 2010的预安装组件里面的。

6、ADO.NET Data Service(强类型)

对于上述那个接口,如果我们使用的是Visual Studio开发后台代码的话,还可以通过Visual Studio的连接到WCF服务的方式,由Visual Studio自动生成一个代理类。这样也可以通过LINQ的方式去进行操作,就像是一个客户端版本的LINQ to SharePoint。实际上,从下面的原理图中我们可以看到,这种方式在服务器端,其实就是通过LINQ to SharePoint来完成的:

image006

由于这种方式是综合了REST协议(客户端连接方式)和LINQ to SharePoint(服务器端处理方式),所以其优劣就是这两者的综合。

[注]如果需要更多关于ADO.NET Data Service的相关使用,可以参考MSDN上的这篇文章:Using the REST Interface

7、总结

通过表格的形式,对上述6种方式做一个比较:

 

服务器端效率

客户端效率

对象是否强类型

数据是否强类型

涵盖功能

开发难度

服务器端对象模型

-

最完整

一般

LINQ to SharePoint

一般

-

仅列表数据

容易

Web Service

较完整

复杂

客户端对象模型

仅Foundation功能

一般

REST

仅列表数据

复杂

强类型ADO.NET Data Service

一般

仅列表数据

容易

于是,当我们选择数据访问方式的时候,就可以得出下面的这种选择路线(一家之言,欢迎讨论):

绘图1

posted on 2012-04-27 01:14  Erucy  阅读(...)  评论(...编辑  收藏

导航