(四)使用SPSiteDataQuery进行多列表查询
1、概述
前面介绍的列表查询有很多优势,但是它的一个缺点就是一次只能在一个列表中进行查询,在SharePoint中,提供了一个跨网站、跨列表查询的机制。通过使用SPSiteDataQuery对象,以及SPWeb的GetSiteData方法,将SPSiteDataQuery作为参数,可以进行跨网站和跨列表的查询。
它与列表查询的相同之处在于:
(1) 使用同样的Query属性确定筛选条件和排序条件(不支持分组条件);
(2) 使用同样的ViewFields属性确定返回字段;
(3) 使用同样的RowLimit属性确定一次返回的条目数。
它与列表查询的不同之处在于:
(1) 可以跨网站跨列表查询(但是有一定的限制,见后文);
(2) 返回的类型是DataTable,而非SPListItemCollection;
(3) 不支持像列表查询那样的分页功能;
(4) 不再有ViewAttributes和Folder指定精细的查询范围;
(5) ViewFields属性返回字段的设置略有差别。
2、同时在多个列表中进行数据查询
通过使用SPSiteDataQuery的Lists属性指定跨列表的范围。
Lists是一个string类型的属性,同样需要使用CAML的格式来定义列表的范围,定义的方法包括如下内容:
(1) 指定列表模板,查询指定列表模板的所有列表,指定方式形如:“<Lists ServerTemplate='TemplateID' />”。其中的TemplateID为列表模板的整型ID,SharePoint内置列表模板的ID可以在SPListTemplateType枚举中查到,例如通知列表模板的ID是104.
(2) 指定列表基类型,查询指定基类型的所有列表,指定方式形如:“<Lists BaseType='BaseTypeID' />”。其中的BaseTypeID是列表基类型的ID,可以通过SPBaseType枚举查到,例如文档库类型的ID为1。
(3) 指定是否查找隐藏列表,默认情况下,跨列表查询时忽略隐藏列表的(比如网站模板库、母版页库等等),可以通过在Lists属性中指定Hidden属性来查找隐藏列表,形如:“<Lists Hidden='TRUE'/>”。
(4)指定查找某些特定的列表,通过列表的Guid可以在某几个特定的列表中进行查找,形如:
1: <Lists>
2: <List ID="7A9FDBE6-0841-430a-8D9A-53355801B5D5" />
3: <List ID="3D18F506-FCA1-451e-B645-2D720DC84FD8" />
4: </Lists>
(5)指定查找包含某个索引字段的列表,形如:
1: <Lists>
2: <WithIndex FieldId="D4819257-6B69-41F1-82C8-A91615BFF500"
3: Type="Text" Value="Complete" />
4: </Lists>
如果默认不指定Lists属性,则其默认值为“<Lists BaseType='0' />”,即相当于查找所有的GenericList(普通列表),并且不包括隐藏列表在内。
需要特别声明的是,尽管提供了上述多种跨列表的方式,但是无论使用哪一种方式,跨列表查询均无法跨越不同的BaseType进行查找。举个例子说,SharePoint无法在跨列表查询的时候,同时查找一个普通列表和一个文档库中的内容,因为它们的BaseType不同。也就是说,如果希望能够查到一个网站中的所有列表,那么就只能进行多次查找,并将找到的DataTable结果拼合在一起。
3、同时在多个网站中进行数据查询
通过使用SPSiteDataQuery的Webs属性进行跨网站查找。
跨网站查找有三种方式:
(1) 默认不指定Webs属性,即查找当前网站;
(2) 使用“<Webs Scope='Recursive'/>”查找当前网站及其所有后代网站;
(3)使用“<Webs Scope='SiteCollection'/>”查找整个网站集。
4、返回字段(栏)
在列表查询中,如果不指定ViewFields这个属性,那么在返回查找结果的时候,是返回列表中的所有字段;而在跨网站跨列表查询中,如果不指定这个属性,则在结果的DataTable中只会返回三个字段:网站ID、列表ID、列表条目ID——通过这个三个ID,就可以唯一确定一个列表条目在网站中的位置。而且这三个字段是无法去掉的。
自然,SPSiteDataQuery也可以和SPQuery一样,通过指定ViewFields属性,返回需要的字段值,不过有两个地方与列表查询有所区别:
(1) SPSiteDataQuery在指定ViewFields的时候,可以通过ListProperty标签返回列表的属性(基本上就是列表的标题),以及通过ProjectProperty标签返回网站的属性(基本上就是网站的标题)。
(2) 因为不同列表可能会存在着结构上的不同,因此在SPSiteDataQuery的ViewFields属性的FieldRef标签中,设置了Nullable属性,放置某个列表字段的缺失。举例来说,如果一个列表1中包含了字段A、B,而列表2中包含了字段A、C,用户希望能够在返回结果的时候返回字段A和B。如果按照原有的方式编写ViewFields属性,那么在列表2中的所有条目都无法被查询到,因为列表2没有需要显示的B字段,为了避免这一情况的发生,可以将属性指定为:“<FieldRef Name='A'/><FieldRef Name='B' Nullable='TRUE' />”。
下面是一个跨网站跨列表查询的例子,例子中查询的是网站集中所有文档库中名字包含“sp”的文档和文件夹:
1: using(SPSite site = new SPSite("http://sp2010/book"))
2: {
3: using(SPWeb web = site.OpenWeb())
4: {
5: SPSiteDataQuery query = new SPSiteDataQuery();
6: query.Query = "<Where><Contains><FieldRef Name='FileLeafRef'/>"
7: + "<Value Type='Text'>sp</Value></Contains></Where>";
8: query.ViewFields = "<FieldRef Name='FileLeafRef'/>" +
9: "<ListProperty Name='Title'/>" +
10: "<ProjectProperty Name='Title'/>";
11: query.Lists = "<Lists BaseType='1' />";
12: query.Webs = "<Webs Scope='SiteCollection' />";
13:
14: DataTable result = web.GetSiteData(query);
15: Console.WriteLine(result.Rows.Count);
16: }
17: }
上面的程序中出于篇幅考虑没有输出DataTable的具体内容,可以使用Visual Studio的调试工具,在输出一行上加入断点,使用调试工具中的DataTable查看器来查看result变量的结果。