SharePoint 2010中新增的GetItemByIdSelectedFields方法

2/3/2010来源:ASP技巧人气:4828

唔……事先声明,其实这篇文章没有太多实际的使用意义,所以想了解某个东东怎么用的同学可以按Alt + F4(或者Ctrl + W)了。想了解SharePoint里面是怎么工作的同学可以继续往下翻。

最近正在和KB一起写关于SharePoint 2010开发方面的一本书,在研究2010新增加的对象模型的时候,偶然发现了这个方法。我们都知道在2003/2007里面,根据ID获取列表条目使用的是SPList的GetItemById方法(什么,没听说过这个方法?那恐怕你不是一个合格的SharePoint开发人员……)。新增加的这个方法名字叫GetItemByIdSelectedFields(同时也增加了一个GetItemByIdAllFields的方法与之作伴,不过这个和GetItemById是完全等效的,就不再废话了),方法的定义是这样的:

   1: public SPListItem GetItemByIdSelectedFields(int id, params string[] fields)
当我第一眼看到这个的时候,立刻就想到了SPQuery的那个ViewFields属性,获取某个列表条目的时候,只返回某些指定的字段,来提高效率。可是当我写了个Console程序试验的时候,发现并不是我想象中的样子,比如我写成(这个方法要求写内部名称):

   1: SPListItem item = spList.GetItemByIdSelectedFields(1, "Title", "Created");   2: Console.WriteLine(item["Modified"]);

这段程序居然没有报错,而且Modified的值也正常返回了,于是我试了试,一个自定义列表里面居然有50来个字段的值都正常返回了,但是所有的查阅项、用户和用户组(其实这个本质上也是查阅项)都没有返回。

在好奇驱使下(暂时还害不死我),我Reflector了一下这个方法的源代码:

   1: if(field == null)   2: {   3:   throw new ArgumentNullException("fields");   4: }   5:     6: StringBuilder builder = new StringBuilder();   7: foreach (string str in fields)   8: {   9:   if (str != null)  10:   {  11:     builder.Append("<FieldRef Name=\"" + str + "\"/>");  12:   }  13: }  14:    15: foreach (SPField field in this.Fields)  16: {  17:   bool flag = false;  18:   foreach (string str2 in fields)  19:   {  20:     if (str2 == field.InternalName)  21:     {  22:       flag = true;  23:       break;  24:     }  25:   }  26:   if (!flag && field.MustFetchByDefault)  27:   {  28:     builder.Append("<FieldRef Name=\"");  29:     builder.Append(field.InternalName);  30:     builder.Append("\"/>");  31:   }  32: }  33:    34: return this.GetItemById(id, null, false, builder.ToString());
关于最后那个GetItemById是怎么回事,暂时先不用再去深究了,只要知道它是一个GetItemById的重载,目的就是查找条目用的就行了,最后一个参数把需要获取的字段以CAML的形式放进去。

第7行那个foreach很好理解,把我们需要的字段加进去;但是第15行的那个foreach一开始就有点让人摸不着头脑了,还要把其他字段也放进去?而且SPField的这个MustFetchByDefault是什么东西?再挖挖看看:

   1: internal bool MustFetchByDefault   2: {   3:   get   4:   {   5:     string fieldAttributeValue = this.GetFieldAttributeValue("List");   6:     if(!string.IsNullOrEmpty(fieldAttributeValue) &&   7:        (fieldAttrbuteValue != GlobalList.Docs.ToString()))   8:     {   9:       return false;  10:     }  11:     return true;  12:   }  13: }


如何判断一个字段是不是要取呢?通过判断字段的一个List属性,至于GetFieldAttributeValue方法就不再往上贴了(否则有骗字数的嫌疑),总之它是从Field的类似Schemaxml属性(字段描述)的Xml结点中,去找一个List的属性。如果找到了,而且不是GlobalList.Docs(某个特殊的东东)的话,那么这个字段就不是必须的,换句话说这个字段我就不用返回给用户。

那什么字段的SchemaXml里会有List属性?一个字段里有一个和列表的属性?查阅项!哈,真的是回避掉了所有的查阅项。(Docs这个东西是“路径”这个字段的List属性,估计有某些特殊的来源)

现在我们知道为什么会包含其他所有字段,并且不包含查阅项了。但是为什么要这样?如果我们对SharePoint的内容数据库有所了解的话,我们会知道其实查阅项在内容数据库里只存了一个ID值在AllUserData表里面(但是用对象模型取出来的时候,是包含查阅那个条目相应字段的内容的),这也就意味着,如果要返回查阅项的值,就需要多做一些额外的数据库操作(比如再去找到被查阅的那个条目,把相应字段的值返回来,拼装成“1;#Administrator“这种鬼样子)。更重要的是,如果这个查阅项是一个多值的,那么这个查阅项本身都是保存在另外一个表中的(AllUserDataJunctions),这样要返回起来还真是要费不少功夫。所以2010里面新增加了这么一个东西,如果我们的列表中包含好多个查阅项,而我们可能暂时只用到其中一两个(或者一个都不用)的话,看来用这个方法确实能提高不少效率。