列表操作 - C#开发人员

SharePoint 2013开发入门探索(二)- 列表操作

我们如何用代码对SharePoint列表做些例如增删改查的操作呢?如果您的程序可以部署到服务器上,就可以使用 服务器对象模型,因为服务器对象模型提供的功能最多,限制最少;否则可能要选择客户对象模型等其他方式,这可能会遇到一些功能限制;另外还有一些其他的访问方式,例如Web服务等。如何在 SharePoint 2013 中选择正确的 API 集请参考链接http://msdn.microsoft.com/zh-cn/library/jj164060.aspx 。

我们首先研究下服务器对象模型。使用服务器对象模型需要到服务器端部署,所以没有服务器部署权限的话就不能使用了。使用服务对象模型要引用程序集Microsoft.SharePoint —— 如果您创建的是SharePoint项目,这个引用默认就会有的。

在服务器对象模型中我经常使用的几个.NET类是SPSite、SPWeb、SPList还有SPListItem,下面简单介绍下这几个类。

网站集 (由一个首要网站以及该网站下的所有网站组成,参考:http://technet.microsoft.com/zh-cn/library/cc262410.aspx )对应的类是SPSite,可以传参网站集URL给SPSite的构造方法创建对象。一般您可以这样用。

using (SPSite spSite = new SPSite("http://SharePointServer/"))
{
                    //TODO......
}

有时候你可能要提升一下权限以场管理员身份执行,则可以用下面的写法——这是服务器对象模型的优势,但是如果项目选择为“部署为沙盒解决方案”则不能提升到场管理员权限。

SPSecurity.RunWithElevatedPrivileges(() =>
 {
         using (SPSite spSite = new SPSite("http://SharePointServer/"))
         {
              //TODO......
         }
});

SharePoint里的 用户 对应的是SPUser类,也可以使用SPUserToken构造网站集对象实现模拟用户身份执行代码。

SPSecurity.RunWithElevatedPrivileges(() =>
      {
        using (SPSite spSite = new SPSite("http://SharePointServer/"))
        {
          SPUser imitatedUser = spSite.RootWeb.EnsureUser(@"contoso\sanzhang");
          SPUserToken token = imitatedUser.UserToken;
          using (SPSite siteWithUser = new SPSite("SharePointServerUrl", token))
          {
            //TODO......
          }
        }
      });

网站 对应的类是SPWeb,SPSite有一个RootWeb属性,是网站集的根网站;SPSite还有个AllWebs属性,是它的所有网站集合(可以用索引访问),要得到SPWeb对象还可以调用SPSite对象的OpenWeb方法,传给一个URL参数(根网站的URL和网站集是相同的,所以下面的代码传空字符串,其他子网站要传标识网站的URL部分)。每个SPWeb对象也有个Webs属性,是这个网站的子网站(也可以用索引访问)。

using (SPSite spSite = new SPSite("http://SharePointServer/"))
{
  //获取网站集根网站对象
  SPWeb spRootWeb = spSite.RootWeb;
  Console.WriteLine("网站集的根网站是{0}", spRootWeb.Title);
  //用网站ID获取子网站对象
  Guid webId = new Guid("{4a106421-ae78-40fd-ad62-77fecb67cf27}");
  SPWeb spWeb = spSite.AllWebs[webId];
  Console.WriteLine("该网站是{0}", spWeb.Title);
  spWeb = spRootWeb.Webs[webId];
  Console.WriteLine("该网站是{0}", spWeb.Title);
  //用网站名称获取子网站对象
  string name = "mysubweb1";
  spWeb = spSite.AllWebs[name];
  Console.WriteLine("该网站是{0}", spWeb.Title);
  spWeb = spRootWeb.Webs[name];
  Console.WriteLine("该网站是{0}", spWeb.Title);
  //用网站URL获取子网站对象
  string url = @"/mysubweb1";
  spWeb = spSite.OpenWeb(url);
  Console.WriteLine("该网站是{0}", spWeb.Title);
}

获取对网站和其他关键对象的引用请参考:http://msdn.microsoft.com/zh-cn/library/ms468609(v=office.14).aspx 。

     列表 对应的类是SPList,其实SPList类对应的不仅仅是狭义的自定义列表,文档库、图片库、日历、通知、任务都可以用它来操作,还有网站资产、用户信息列表、解决方案库、列表模版库、Web部件库等等。SPWeb对象有个Lists属性,是SPListCollection类型,遍历它或者用ID、Title做索引可得到SPList对象。想了解网站中有哪些List可以用下面的代码查看:

//获取网站所有列表
          foreach (SPList list in spWeb.Lists)
          {
            Console.WriteLine("Title:{0} BaseType:{1} BaseTemplate:{2}", list.Title, list.BaseType, list.BaseTemplate);
          }
          //用列表标题获取列表对象
          string title = @"我的客户列表";
          SPList spList = spWeb.Lists[title];
          Console.WriteLine("该列表是{0}。", spList.Title);
          //用列表ID获取列表对象
          Guid id = new Guid(@"{3824b091-c7b8-409c-bcc0-7cce487d6b49}");
          spList = spWeb.Lists[id];
          Console.WriteLine("该列表是{0}。", spList.Title);
          //用列表URL获取列表对象
          string listUrl = string.Format(@"{0}/{1}", spWeb.Url, "Lists/MyCustomerList/AllItems.aspx");
          spList = spWeb.GetList(listUrl);
          Console.WriteLine("该列表是{0}。", spList.Title);

您还是否记得这些列表属性,我们在开发自定义列表时都设置过?

      列表项 对应的类是SPListItem,SPList对象的Items属性是它的项目的集合,是SPListItemCollection类型的,枚举它的元素就是SPListItem对象了。不过您想访问列表项的时候一般不要直接通过SPList对象的Items属性,特别是已经存储了很多项目的大数据列表,因为可能会有不必要的数据加载影响性能。例如您想知道列表中已存在多少个项目,可以直接访问SPList对象的ItemCount属性,而不是SPList对象的Items属性的Count;如果您想得到列表中的某个项目可以调用SPList对象的GetItemById、GetItemByUniqueId等方法。

//用列表标题获取列表对象
  SPList spList = spWeb.Lists["我的客户列表"];
  //获取用户信息列表的项目数量
  int userCount = spList.ItemCount;
  Console.WriteLine("我的客户列表共有{0}条项目。", userCount.ToString());
  //用项目ID获取项目对象
  int itemId = 18;
  SPListItem spListItem = spList.GetItemById(itemId);
  Console.WriteLine("该客户是{0}。", spListItem.Title);
  //用项目UniqueID获取项目对象
  Guid itemUniqueId = new Guid("{83815a27-6291-416d-8db6-a77bcae4bb86}");
  spListItem = spList.GetItemByUniqueId(itemUniqueId);
  Console.WriteLine("该客户是{0}。", spListItem.Title);

列表对象还有一个Fields的属性,是SPFieldCollection类型,遍历这个字段集合可以得到SPField对象。这就是列表的字段信息,包括字段内部名称、显示名称、类型等等。我们要访问列表项目的某个属性时就可以用SPField对象的ID,InternalName或Title。

string title = @"我的客户列表";
          SPList spList = spWeb.Lists[title];
          SPFieldCollection spFields = spList.Fields;
          //获取列表的字段信息
          foreach (SPField field in spFields)
          {
            Console.WriteLine("Title:{0}  InternalName:{1}  TypeDisplayName:{2}  TypeAsString:{3}", field.Title, field.InternalName, field.TypeDisplayName, field.TypeAsString);
          }
          Guid fieldId = new Guid("{a943ca8c-a2ad-4a90-8a78-2f6a202f6553}");
          SPField spField = spFields[fieldId];
          SPListItem spListItem = spList.Items[0];
          //用字段的ID访问列表项目属性
          Console.WriteLine("该用户的消费金额是{0}。", spListItem[spField.Id].ToString());
          //用字段的InternalName访问列表项目属性
          Console.WriteLine("该用户的消费金额是{0}。", spListItem[spField.InternalName].ToString());
          Console.WriteLine("该用户的消费金额是{0}。", spListItem.GetFormattedValue(spField.InternalName));
          //用字段的Title访问列表项目属性
          Console.WriteLine("该用户的消费金额是{0}。", spListItem[spField.Title].ToString());
          Console.WriteLine("该用户的消费金额是{0}。", spListItem.GetFormattedValue(spField.Title));

您还记得开发自定义列表栏的时候我们一起设置的那些字段属性吗?

SPList对象还有个GetItemByIdAllFields方法和GetItemByIdSelectedFields方法。看来我们可以按需索取项目字段了。

//用列表标题获取列表对象
  string title = @"我的客户列表";
  SPList spList = spWeb.Lists[title];
  int itemId = 1;
  SPListItem spListItem = spList.GetItemByIdSelectedFields(itemId, new[] { "CustomerName", "Recency", "Frequency", "Monetary" });
  //用项目的ID和字段的InternalName访问列表项目
  Console.WriteLine("客户{0}的最近消费时间是{1}消费频率是{2}消费金额是{3}。", spListItem["CustomerName"].ToString(), spListItem["Recency"].ToString(), spListItem["Frequency"].ToString(), spListItem["Monetary"].ToString());

不过,我把GetItemByIdSelectedFields方法的数组参数减掉了两个项"Frequency"和"Monetary"再运行,竟然没有看到我期待的、闪电般美丽的异常!不是说只要两个字段吗?而且随后我把SPListItem对象的Xml属性也输出时有看到了好多不是我指定索取的字段信息!

string title = @"我的客户列表";
  SPList spList = spWeb.Lists[title];
  int itemId = 1;
  //删掉"Frequency"、 "Monetary"
  SPListItem spListItem = spList.GetItemByIdSelectedFields(itemId, new[] { "CustomerName", "Recency"});
  //用项目的ID和字段的InternalName访问列表项目
  Console.WriteLine("客户{0}的最近消费时间是{1}消费频率是{2}消费金额是{3}。", spListItem["CustomerName"].ToString(), spListItem["Recency"].ToString(), spListItem["Frequency"].ToString(), spListItem["Monetary"].ToString());
  Console.WriteLine(@"XML:{0}",spListItem.Xml);

查看一下GetItemByIdSelectedFields方法的源代码,发现在拼接CAML查询字段时有个对SPField对象MustFetchByDefault的判断,如果这个属性是True,没有指定也会查询,而且这个SPField对象MustFetchByDefault属性是internal的。

public SPListItem GetItemByIdSelectedFields(int id, params string[] fields)
{
  if (fields == null)
  {
    throw new ArgumentNullException("fields");
  }
  StringBuilder builder = new StringBuilder();
  foreach (string str in fields)
  {
    if (str != null)
    {
      builder.Append("<FieldRef Name=\"" + str + "\"/>");
    }
  }
  foreach (SPField field in this.Fields)
  {
    bool flag = false;
    foreach (string str2 in fields)
    {
      if (str2 == field.InternalName)
      {
        flag = true;
        break;
      }
    }
    if (!flag && field.MustFetchByDefault)
    {
      builder.Append("<FieldRef Name=\"");
      builder.Append(field.InternalName);
      builder.Append("\"/>");
    }
  }
  return this.GetItemById(id, null, false, builder.ToString());
}

如何读取列表项中字段的值请参考: http://msdn.microsoft.com/zh-cn/library/ff521580(v=office.14).aspx 。

在读取项目属性时,有些类型是比较特殊的:例如多个用户或用户组,它可以转为SPFieldUserValueCollection类型,这是个SPFieldUserValue对象的集合; 用户或用户组 、超链接或图片这样的字段取出来时String类型,您要解析可以用字符串截取方式,也可以对应构造成SPFieldUserValue、SPFieldUrlValue对象,直接访问它们的属性。

SPListItem spListItem = spList.GetItemById(itemId);
          //直接ToString,用户是[ID]+[;#] + [显示名];链接是[URL] + [,] + [显示文本]
          Console.WriteLine("客户的分享者是{0} 所有者是{1} 业务系统链接是{2}。", spListItem["Sharers"], spListItem["Owner"].ToString(), spListItem["BusinessPage"].ToString());
          //截取字符串取属性
          Console.WriteLine("客户的所有者的显示名是{0} 业务系统链接的URL是{1}。", spListItem["Owner"].ToString().Split(new[] { @";#" }, StringSplitOptions.None)[1], spListItem["BusinessPage"].ToString().Split(‘,‘)[0]);
          //转为相应对象取属性
          SPFieldUserValueCollection shares = (SPFieldUserValueCollection)spListItem["Sharers"];
          foreach (SPFieldUserValue share in shares)
          {
            if (share.User != null)
            {
              SPUser user = share.User;
              Console.WriteLine(@"找到个用户{0}", user.Name);
            }
            else
            {
              SPGroup spGroup = spWeb.Groups.GetByID(share.LookupId);
              Console.WriteLine(@"找到个用户组{0}", spGroup.Name);
            }
          }
          SPFieldUserValue owner = new SPFieldUserValue(spWeb, spListItem["Owner"].ToString());
          SPFieldUrlValue businessPage = new SPFieldUrlValue(spListItem["BusinessPage"].ToString());
          Console.WriteLine("客户的业务系统链接的URL是{0} 业务系统链接的描述是{1}。", businessPage.Url, businessPage.Description);

如果您想按某些条件得到列表中的几个项目,则可以使用CAML列表查询了。上文中我们查看SPList的源代码,看到了一段XML的拼接,这就是CAML。协作应用程序标记语言 (CAML) 简介请参考:http://msdn.microsoft.com/zh-cn/library/ms426449.aspx 。

如果要直接使用CAML做查询可以使用SPList对象的GetItems方法,这个方法的参数是一个SPQuery对象。SPQuery对象的ViewFields是返回字段(个人理解ViewFieldsOnly要设置为True时ViewFields才有效,但是我尝试中发现不设置“ViewFieldsOnly=true”返回的结果是一样的。另外,ID、Created、Modified等属性一直会被返回的),Query是查询条件,这就相当于SQL语句里的"SELECT ..."和“WHERE...”了。GetItems方法的返回值是一个SPListItemCollection对象,如果喜欢用DataTable的话,可以调用它的GetDataTable()对象。举个简单的查询例子,查询名称为张三的客户:

SPList spList = spWeb.Lists[title];
  SPQuery spQuery = new SPQuery();
  spQuery.ViewFields = @"<FieldRef Name=‘CustomerName‘/><FieldRef Name=‘Gender‘/><FieldRef Name=‘Monetary‘/><FieldRef Name=‘BusinessPage‘/><FieldRef Name=‘Owner‘/><FieldRef Name=‘Sharers‘/>";
  //spQuery.ViewFieldsOnly = true;
  spQuery.Query = @"<Where><Eq><FieldRef Name=‘CustomerName‘/><Value Type=‘Text‘>张三</Value></Eq></Where>";
  SPListItemCollection spListItemCollection = spList.GetItems(spQuery);
  //将结果保存到DataTable
  DataTable dataTable = spListItemCollection.GetDataTable();
  Console.WriteLine(spQuery.ViewFieldsOnly.ToString());
  if (spListItemCollection.Count > 0)
  {
      foreach (SPListItem spListItem in spListItemCollection)
      {
          Console.WriteLine(spListItem["CustomerName"]);
          Console.WriteLine(spListItem.Xml);
      }
  }

CAML查询条件有很多比较符:Eq(=)、Gt(>)、Lt(<)、Geq(>=)、Leq(<=)、Neq(<>)、Contains(Like)、IsNull(Null)、IsNotNull(NotNull)等,多个查询条件可以使用关系运算符And或Or(http://msdn.microsoft.com/zh-cn/library/ms467521(v=office.14).aspx)。再举一个例子:自定义列表-我的客户列表有一个Sharers字段(表示分享用户列表),这个字段可存储多个用户和组,现在有一个用户甲,要查询分享给这个用户或这个用户所在的组的数据则使用如下代码:

string title = @"我的客户列表";
          SPList spList = spWeb.Lists[title];
          SPUser user = spWeb.EnsureUser(loginName);
          SPGroup[] groups = user.Groups.Cast<SPGroup>().ToArray();
          SPQuery spQuery = new SPQuery();
          spQuery.ViewFields = @"<FieldRef Name=‘CustomerName‘/><FieldRef Name=‘Gender‘/><FieldRef Name=‘Monetary‘/><FieldRef Name=‘BusinessPage‘/><FieldRef Name=‘Owner‘/><FieldRef Name=‘Sharers‘/>";
          spQuery.ViewFieldsOnly = true;
          if (groups.Length > 0)
          {
            StringBuilder query = new StringBuilder();
            query.AppendFormat(@"<Where><Or><Includes><FieldRef Name=‘Sharers‘ LookupId=""TRUE"" /><Value Type=‘User‘>{0}</Value></Includes>", user.ID.ToString());
            Array.ForEach(groups, g => query.AppendFormat(@"<Includes><FieldRef Name=‘Sharers‘ LookupId=‘TRUE‘ /><Value Type=‘Group‘>{0}</Value></Includes>", g.ID.ToString()));
            query.Append(@"</Or></Where>");
            spQuery.Query = query.ToString();
          }
          else
          {
            spQuery.Query = string.Format(@"<Where><Includes><FieldRef Name=‘Sharers‘ LookupId=‘TRUE‘ /><Value Type=‘User‘>{0}</Value></Includes></Where>", user.ID.ToString());
          }
          DataTable dataTable = spList.GetItems(spQuery).GetDataTable();

SPQuery对象的ViewAttributes属性可以设置检索范围;RowLimit是返回数量ListItemCollectionPosition是查询位置,用这两个属性可以实现分页查询;列表中如果包含文件夹并且查询要在指定文件夹下执行,可以使用Folder属性。

SPQuery类使用请参考 http://technet.microsoft.com/zh-cn/library/microsoft.sharepoint.spquery.aspx  ;如果您需要跨网站多列表混合查询,可以使用SPSiteDataQuery 类, http://msdn.microsoft.com/zh-cn/library/microsoft.sharepoint.spsitedataquery.aspx ;查询列表项请参考 http://msdn.microsoft.com/zh-cn/library/ms456030(v=office.14).aspx。如果您觉得拼写CAML有些麻烦,也可以到网站找一些小工具下载使用,例如: http://sharepointcamlhelper.codeplex.com/ 。关于查询性能,有几篇个人觉得不错的文章: http://msdn.microsoft.com/zh-cn/subscriptions/ee557257.aspx ,http://www.infoq.com/cn/articles/SharePoint-Andreas-Grabner 。

新增列表项目可以先调用SPList对象的AddItem方法,获取一个新的SPListItem对象,在给SPListItem的所需字段赋值后再调用它的Update方法即可保存新增(SPListItem对象还有个SystemUpdate方法,这个方法在修改时不会影响修改时间和修改者,另外还可以用参数指定是否创建新版本)。

SPUser user1 = spWeb.EnsureUser(loginName1);
  SPUser user2 = spWeb.EnsureUser(loginName2);
  SPGroup group1 = spWeb.Groups[loginName3];
  string title = @"我的客户列表";
  SPList spList = spWeb.Lists[title];
  SPListItem spListItem = spList.AddItem();
  spListItem["CustomerName"] = "赵六";
  spListItem["Gender"] = "女";
  spListItem["EMail"] = "liuzhao@contoso.com";
  spListItem["CellPhone"] = "13456435678";
  spListItem["WorkAddress"] = "西直门";
  spListItem["Recency"] = DateTime.Now;
  spListItem["Frequency"] = 0.5;
  spListItem["Monetary"] = 100000;
  spListItem["BusinessPage"] = new SPFieldUrlValue() { Url = "http://zhaoliu.com", Description = "赵六的个人主页" };
  spListItem["CustomerType"] = "钻石";
  spListItem["Owner"] = new SPFieldUserValue(spWeb, user1.ID, user1.Name);
  spListItem["Sharers"] = new SPFieldUserValueCollection
  {
      new SPFieldUserValue(spWeb, user1.ID, user1.Name),
      new SPFieldUserValue(spWeb, user2.ID, user2.Name),
      new SPFieldUserValue(spWeb, group1.ID, group1.Name)
  };
  spListItem.Update();

在给项目的字段赋值时,对于用户或用户组、超链接或图片这样的字段,也可以直接以字符串赋值。用户或用户组的ID和显示名要以“;#”连接,超链接或图片则以“,”连接URL和描述。

spListItem["BusinessPage"] = string.Format(@"{0},{1}", "http://sunqi.com", "孙七的个人主页");
                    spListItem["Owner"] = new SPFieldUserValue(spWeb, string.Format(@"{0};#{1}", user2.ID.ToString(), user2.Name));
                    spListItem["Sharers"] = string.Join(@";#", user1.ID.ToString(), user1.Name, user2.ID.ToString(), user2.Name, group1.ID.ToString(), group1.Name);

如果项目有个附件文件如何上传呢?这个还很简单,只要使用SPListItem对象的Attachments属性就可以了。这是一个SPAttachmentCollection类型的SPAttachment集合,它有一个Add方法。

spListItem.Attachments.Add(Path.GetFileName(@"C:\1.txt"), File.ReadAllBytes(@"C:\1.txt"));

上文我们提到,对文档库的操作也要使用SPList类,可是我看了一下SPListItem对象的File属性——它是只读的。 那么如何给文档库创建文件夹和上传文件呢?这次创建文件夹或文件的项目要用到SPList对象的AddItem重载方法,相关的SPFolder和SPFile也可以通过列表的网站SPWeb对象获取。

string title = @"我的文档库";
  SPList spList = spWeb.Lists[title];
  //创建一个文件夹的SPListItem对象
  SPListItem folderListItem = spList.AddItem(spList.RootFolder.ServerRelativeUrl, SPFileSystemObjectType.Folder, "文件夹2");
  folderListItem.Update();
  //找到网站对应文件夹SPFolder对象
  SPFolder spFolder = spList.ParentWeb.GetFolder(folderListItem.UniqueId);
  bool allowUnsafeUpdates = spWeb.AllowUnsafeUpdates;//如果AllowUnsafeUpdates是False可能下面操作会有异常
  spWeb.AllowUnsafeUpdates = true;
  //在指定文件夹下添加文件
  spFolder.Files.Add(Path.GetFileName(@"C:\1.txt"), File.ReadAllBytes(@"C:\1.txt"));
  spWeb.AllowUnsafeUpdates = allowUnsafeUpdates;

再看看修改和删除列表项目就非常简单了。(参考资料:http://msdn.microsoft.com/zh-cn/library/ms467435(v=office.14).aspx )

string title = @"我的客户列表";
  SPList spList = spWeb.Lists[title];
  //修改:
  int itemId = 5;
  SPListItem spListItem = spList.GetItemById(itemId);
  spListItem["CustomerName"] = "孙七七";
  spListItem.Update();
  //删除:
  //spListItem.Delete();

不过要高效的批量执行增删改操作还是需要SPWeb对象的ProcessBatchData方法。命令语法请参考: http://msdn.microsoft.com/zh-CN/library/ms455433(v=office.12).aspx 、 http://msdn.microsoft.com/zh-cn/library/microsoft.sharepoint.spweb.processbatchdata.aspx 、http://msdn.microsoft.com/zh-cn/library/cc404818.aspx 。下面代码是插入、修改和删除的例子,对于多个用户和组、超链接或图片还是使用的字符串拼接(用户和组用“;#”连接ID和显示名称,超链接或图片用空格+逗号+空格连接URL和描述),还有时间类型字段,要转换为ISO8601格式,可以调用SPUtility类的CreateISO8601DateTimeFromSystemDateTime方法创建(http://msdn.microsoft.com/zh-cn/library/ms197282(v=office.14).aspx )。

SPUser user1 = spWeb.EnsureUser(loginName1);
  SPUser user2 = spWeb.EnsureUser(loginName2);
  SPGroup group1 = spWeb.Groups[loginName3];
  string listId = @"3824b091-c7b8-409c-bcc0-7cce487d6b49";
  StringBuilder strBatchData = new StringBuilder(@"<?xml version=""1.0"" encoding=""UTF-8""?><Batch>");
  //命令头:
  string setListText = string.Format(@"<SetList Scope=""Request"">{0}</SetList>", listId);
  //插入数据:
  strBatchData.AppendFormat(@"<Method ID=""Insert,1"">{0}<SetVar Name=""ID"">New</SetVar><SetVar Name=""Cmd"">Save</SetVar>", setListText);
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "CustomerName", "蒋九");
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Gender", "男");
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "EMail", "[email protected]");
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "CellPhone", "13656435678");
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "WorkAddress", "菜市口");
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Recency", SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now.AddDays(-1)));
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Frequency", "0.3");
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Monetary", "30000");
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "BusinessPage", string.Format(@"{0} , {1}", "http://jiangjiu.com", "蒋九的个人主页"));
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "CustomerType", "青铜");
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Owner", string.Format(@"{0};#{1}", user2.ID.ToString(), user2.Name));
  strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Sharers", string.Join(@";#", user1.ID.ToString(), user1.Name, user2.ID.ToString(), user2.Name, group1.ID.ToString(), group1.Name));
  strBatchData.Append("</Method>");
  //修改数据:
  string updateItemId = "2";
  strBatchData.AppendFormat(@"<Method ID=""Update,1"">{0}<SetVar Name=""ID"">{1}</SetVar><SetVar Name=""Cmd"">Save</SetVar><SetVar Name=""urn:schemas-microsoft-com:office:office#{2}"">{3}</SetVar></Method>", setListText, updateItemId, "CustomerName", "李四四");
  //删除数据:
  string deleteItemId = "3";
  strBatchData.AppendFormat(@"<Method ID=""Delete,1"">{0}<SetVar Name=""ID"">{1}</SetVar><SetVar Name=""Cmd"">Delete</SetVar></Method>", setListText, deleteItemId);
  //命令尾:
  strBatchData.Append(@"</Batch>");
  //执行:
  Console.WriteLine(spWeb.ProcessBatchData(strBatchData.ToString()));

服务端对象模型还有一个很重要的上下文对象--SPContext,在开发Web部件时经常会用到。我们可以通过SPContext.Current获取到当前上下文SPContext对象,用该对象可以直接获取当前网站、当前列表、当前项目......(http://msdn.microsoft.com/zh-cn/library/microsoft.sharepoint.spcontext.aspx )

SPContext spContext = SPContext.Current;
  //当前网站集
  SPSite spSite = spContext.Site;
  //当前网站
  SPWeb spWeb = spContext.Web;
  //当前用户
  SPUser spUser = spWeb.CurrentUser;
  //当前列表
  SPList spList = spContext.List;
  //当前列表ID
  Guid listId = spContext.ListId;
  //当前项目
  SPItem spItem = spContext.Item;
  //当前项目ID
  int itemId = spContext.ItemId;
  //当前项目ID(字符串)
  string itemIdAsString = spContext.ItemIdAsString;
  //当前页面上下文
  SPContextPageInfo contextPageInfo = spContext.ContextPageInfo;
  //......


上文花了较大篇幅研究服务端对象模型,接下来我们研究托管客户端对象模型(托管客户端对象模型是用.NET开发的,另有ECMAScript客户端对象模型以后会介绍, http://msdn.microsoft.com/zh-cn/library/ee539429(v=office.14).aspx )。客户端对象模型不需要部署到服务器端,当然功能也会有一定限制。使用客户端对象模型代码需要引用Microsoft.SharePoint.Client程序集和Microsoft.SharePoint.Client命名空间。

首先,我们要构建一个客户端上下文对象——ClientContext(相当于服务端对象模型的Microsoft.SharePoint.SPContext)。如果需要显式以某个用户的 Windows 凭据运行,可以给ClientContext对象的Credentials赋值。()

ClientContext clientContext = new ClientContext(webFullUrl);
            //NetworkCredential networkCredential = CredentialCache.DefaultNetworkCredentials;
            //clientContext.Credentials = networkCredential;
            NetworkCredential networkCredential = new NetworkCredential(@"contoso\administrator", "password");
            clientContext.Credentials = networkCredential;

使用过了服务器端对象模型再理解客户端对象模型比较容易,与Microsoft.SharePoint.SPList对应的是Microsoft.SharePoint.Client.List、与Microsoft.SharePoint.SPListItem对应的是Microsoft.SharePoint.Client.ListItem,只是客户端对象模型要写更多代码,通过查询取得的对象不能直接使用,需要调用ClientContext对象的Load方法,并显式调用ExecuteQuery方法。( http://msdn.microsoft.com/zh-cn/library/ee534956(v=office.14).aspx 、 http://msdn.microsoft.com/zh-cn/library/gg277498.aspx )

string webFullUrl = "http://SharePointServer/";
      using (ClientContext clientContext = new ClientContext(webFullUrl))
      {
        List list = clientContext.Web.Lists.GetByTitle("我的客户列表");
        CamlQuery camlQuery = new CamlQuery();
        //指定过滤条件
        camlQuery.ViewXml = @"<View><Query><Where><Eq><FieldRef Name=‘CustomerName‘/><Value Type=‘Text‘>蒋九</Value></Eq></Where></Query></View>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        //加载查询,并指定加载字段:
        clientContext.Load(listItems,
          items => items.Include(
            item => item.Id,
            item => item["CustomerName"],
            item => item["Gender"],
            item => item["EMail"],
            item => item["CellPhone"],
            item => item["WorkAddress"],
            item => item["Recency"],
            item => item["Frequency"],
            item => item["Monetary"],
            item => item["BusinessPage"],
            item => item["CustomerType"],
            item => item["Owner"],
            item => item["Sharers"]));
        //执行查询
        clientContext.ExecuteQuery();
        int count = listItems.Count;
        foreach (ListItem item in listItems)
        {
          Console.WriteLine("ID: {0} CustomerName: {1} Gender: {2}  EMail: {3} CellPhone: {4}  WorkAddress: {5}  Recency: {6}  Frequency: {7}  Monetary: {8} BusinessPage: {9} CustomerType: {10} Owner: {11} Sharers: {12} ",
          item.Id, item["CustomerName"], item["Gender"], item["EMail"], item["CellPhone"],
          item["WorkAddress"], item["Recency"], item["Frequency"], item["Monetary"],
          ((FieldUrlValue)item["BusinessPage"]).Url, item["CustomerType"], ((FieldUserValue)item["Owner"]).LookupValue, string.Join(",", ((FieldUserValue[])item["Sharers"]).Select(v => v.LookupValue).ToArray()));
        }
      }

新增项目时也多了一个步骤,要先创建一个ListItemCreationInformation对象(添加附件还要创建AttachmentCreationInformation对象),再调用List的AddItem方法;为ListItem对象的属性赋值后,要调用Update和ExecuteQuery方法。

Guid listId = new Guid(@"{3824b091-c7b8-409c-bcc0-7cce487d6b49}");
  List list = clientContext.Web.Lists.GetById(listId);
  ListItemCreationInformation listItemCreationInformation = new ListItemCreationInformation();
  ListItem listItem = list.AddItem(listItemCreationInformation);
  listItem["CustomerName"] = "李四";
  listItem["Gender"] = "女";
  listItem["EMail"] = "[email protected]";
  listItem["CellPhone"] = "13456435678";
  listItem["WorkAddress"] = "西直门";
  listItem["Recency"] = DateTime.Now;
  listItem["Frequency"] = 0.5;
  listItem["Monetary"] = 100000;
  listItem["BusinessPage"] = new FieldUrlValue() {  Url = "http://lisi.com", Description = "李四的个人主页" };
  listItem["CustomerType"] = "钻石";
  listItem["Owner"] = FieldUserValue.FromUser(loginName1);
  listItem["Sharers"] = new []
          {
    FieldUserValue.FromUser(user1.LoginName),
    FieldUserValue.FromUser(user2.LoginName),
    FieldUserValue.FromUser(group1.LoginName)
          };
  listItem.Update();
            AttachmentCreationInformation attachmentCreationInformation = new AttachmentCreationInformation();
  using (FileStream fileStream = new FileStream(fileFullName, FileMode.Open))
  {
      attachmentCreationInformation.ContentStream = fileStream;
      attachmentCreationInformation.FileName = Path.GetFileName(fileFullName);
      listItem.AttachmentFiles.Add(attachmentCreationInformation);
      clientContext.ExecuteQuery();
  }

如果要上传一个文档到文档库则需要创建FileCreationInformation对象。

string title = @"我的文档库";
  List list = clientContext.Web.Lists.GetByTitle(title);
  Folder folder = list.RootFolder.Folders.Add("文件夹1");
  folder.Update();
  FileCreationInformation fileCreationInformation = new FileCreationInformation();
  fileCreationInformation.Content = System.IO.File.ReadAllBytes(fileFullName);
  fileCreationInformation.Overwrite = true;
  fileCreationInformation.Url = Path.GetFileName(fileFullName);
  folder.Files.Add(fileCreationInformation);
  clientContext.ExecuteQuery();

将项目修改或删除的代码很简单,也是操作后要调用ListItem对象的Update和ExecuteQuery方法。( http://msdn.microsoft.com/zh-cn/library/ee539976(v=office.14).aspx )

Guid listId = new Guid(@"{3824b091-c7b8-409c-bcc0-7cce487d6b49}");
  int itemId = 14;
  List list = clientContext.Web.Lists.GetById(listId);
  ListItem item = list.GetItemById(itemId);
  clientContext.Load(item);
  clientContext.ExecuteQuery();
  //修改
  item["CustomerName"] = "蒋九九";
  item.Update();
  clientContext.ExecuteQuery();
  //删除
  item.DeleteObject();
  clientContext.ExecuteQuery();


关于Web Services( http://msdn.microsoft.com/zh-cn/library/dd878586(v=office.12).aspx )的方式操作列表,首先要添加Web引用(解决方案资源管理器-〉引用-〉添加服务引用-〉高级(左下角)-〉添加Web引用(左下角)-〉URL输入框输入 http://<site>/_vti_bin/Lists.asmx .)。

这里的操作命令语法和服务器端对象模型、客户端对象模型里的CAML非常相似,只是Web服务方法的参数和返回值多是XmlDocument对象,查询列表项目shiyongLists.GetListItems 方法(请参考:http://msdn.microsoft.com/zh-cn/library/websvclists.lists.updatelistitems(v=office.12).aspx ),下面是一个简单的查询例子。

string listName = "我的客户列表";
      using (Lists listService = new Lists())
      {
        listService.Credentials = CredentialCache.DefaultCredentials;
        //或者:
        //listService.Credentials = new NetworkCredential(@"contoso\administrator", "password");
        XmlDocument xmlDocument = new XmlDocument();
        XmlNode queryNode = xmlDocument.CreateNode(XmlNodeType.Element, "Query", string.Empty);
        XmlNode viewFieldsNode =
          xmlDocument.CreateNode(XmlNodeType.Element, "ViewFields", string.Empty);
        viewFieldsNode.InnerXml = @"<FieldRef Name=‘ID‘ /><FieldRef Name=‘CustomerName‘ /><FieldRef Name=‘Gender‘ /><FieldRef Name=‘EMail‘ /><FieldRef Name=‘CellPhone‘ />";
        queryNode.InnerXml = string.Format(@"<Where><Eq><FieldRef Name=‘CustomerName‘/><Value Type=‘Text‘>{0}</Value></Eq></Where>", "蒋九");
        XmlNode resultNode = listService.GetListItems(listName, null, queryNode, viewFieldsNode, null, null, null);
        Console.WriteLine(resultNode.InnerXml);
        Console.ReadLine();
        }

新增、修改、删除列表项目使用Lists.UpdateListItems 方法执行批量命令(请参考: http://msdn.microsoft.com/zh-cn/library/websvclists.lists.updatelistitems(v=office.12).aspx )。对于多个用户和组、超链接或图片等特殊的字段类型还是使用的和服务器端对象模型相同的字符串拼接。

      string listName = "我的客户列表";
      using (Lists listService = new Lists())
      {
        listService.Credentials = CredentialCache.DefaultCredentials;
        //或者:
        //listService.Credentials = new NetworkCredential(@"contoso\administrator", "password");
        XmlDocument xmlDocument = new XmlDocument();
        XmlElement updatesBatch = xmlDocument.CreateElement("Batch");
        updatesBatch.SetAttribute("OnError", "Continue");
        StringBuilder methodsText = new StringBuilder();
        //删除数据:
        methodsText.AppendFormat(@"<Method ID=‘Delete,1‘ Cmd=‘Delete‘><Field Name=‘ID‘>{0}</Field></Method>", deleteItemId.ToString());
        //插入数据:
        methodsText.Append(@"<Method ID=‘Insert,1‘ Cmd=‘New‘><Field Name=‘ID‘>New</Field>");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "CustomerName", "蒋九");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Gender", "男");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "EMail", "[email protected]");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "CellPhone", "13656435678");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "WorkAddress", "菜市口");
        DateTime recency = DateTime.Now.AddDays(-1);
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Recency", string.Format("{0}-{1}-{2}T{3}:{4}:{5}Z", recency.Year.ToString("0000"), recency.Month.ToString("00"), recency.Day.ToString("00"), recency.Hour.ToString("00"), recency.Minute.ToString("00"), recency.Second.ToString("00")));
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Frequency", "0.4");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Monetary", "10000");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "BusinessPage", string.Format(@"{0} , {1}", "http://jiangjiu.com", "蒋九的个人主页"));
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "CustomerType", "青铜");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Owner", string.Format(@"{0};#{1}", user2.ID.ToString(), user2.Name));
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Sharers", string.Join(@";#", user1.ID.ToString(), user1.Name, user2.ID.ToString(), user2.Name, group1.ID.ToString(), group1.Name));
        methodsText.Append("</Method>");
        methodsText.Append(@"<Method ID=‘Insert,2‘ Cmd=‘New‘><Field Name=‘ID‘>New</Field>");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "CustomerName", "孙七");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Gender", "女");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "EMail", "[email protected]");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "CellPhone", "13656437456");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "WorkAddress", "恭王府");
        DateTime recency2 = DateTime.Now.AddDays(-3);
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Recency", string.Format("{0}-{1}-{2}T{3}:{4}:{5}Z", recency2.Year.ToString("0000"), recency2.Month.ToString("00"), recency2.Day.ToString("00"), recency2.Hour.ToString("00"), recency2.Minute.ToString("00"), recency2.Second.ToString("00")));
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Frequency", "0.6");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Monetary", "10000");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "BusinessPage", string.Format(@"{0} , {1}", "http://sunqi.com", "孙七的个人主页"));
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "CustomerType", "黄金");
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Owner", string.Format(@"{0};#{1}", user2.ID.ToString(), user2.Name));
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "Sharers", string.Join(@";#", user1.ID.ToString(), user1.Name, user2.ID.ToString(), user2.Name, group1.ID.ToString(), group1.Name));
        methodsText.Append("</Method>");
        //修改数据:
        methodsText.AppendFormat(@"<Method ID=‘Update,1‘ Cmd=‘Update‘><Field Name=‘ID‘>{0}</Field>", updateItemId.ToString());
        methodsText.AppendFormat(@"<Field Name=‘{0}‘>{1}</Field>", "CustomerName", "赵六六");
        methodsText.Append("</Method>");
        updatesBatch.InnerXml = methodsText.ToString();
        XmlNode returnNode = listService.UpdateListItems(listName, updatesBatch);
        Console.WriteLine(returnNode.InnerXml);
       }
时间: 2024-10-12 15:24:06

列表操作 - C#开发人员的相关文章

国内及Github优秀开发人员列表

自从入了Android软件开发的行道,解决问题和学习过程中免不了会参考别人的思路,浏览博文和门户网站成了最大的入口.下面这些列表取名为:国内及Github优秀开发人员列表,就是浏览后的成果. 虽然下述列表出自Android软件开发,文章定为不断更新并涉及更多领域. 谓之优秀,唯坚持也. 1. _区长 专注Android开发,专栏有:Android React Native/Android中的设计模式/Android开发最佳实践/Android ORM/Android插件化开发 https://g

SharePoint 2013开发入门探索(二)- 列表操作

我们如何用代码对SharePoint列表做些例如增删改查的操作呢?如果您的程序可以部署到服务器上,就可以使用 服务器对象模型,因为服务器对象模型提供的功能最多,限制最少:否则可能要选择客户对象模型等其他方式,这可能会遇到一些功能限制:另外还有一些其他的访问方式,例如Web服务等.如何在 SharePoint 2013 中选择正确的 API 集请参考链接 http://msdn.microsoft.com/zh-cn/library/jj164060.aspx. 我们首先研究下服务器对象模型.使用

python开发基础:列表操作

一,列表操作 1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 4 # l=[1,2,3] #l=list([1,2,3]) 5 # print(type(l)) 6 7 #pat1===>优先掌握部分 8 # 索引 9 # 10 # 切片 11 # l=['a','b','c','d','e','f'] 12 13 # print(l[1:5]) 14 # print(l[1:5:2]) 15 # print(l[2:5]) 16 # print(

Front End Developer Questions 前端开发人员问题(二)

问题来源:http://markyun.github.io/2015/Front-end-Developer-Questions/ 二.CSS 1.介绍一下标准的CSS的盒子模型?与低版本IE的盒子模型有什么不同的?答:标准的CSS盒子模型:宽度=内容的宽度+边框的宽度+内边距宽度低版本的盒子模型:指的是内容的宽度 2.CSS选择符有哪些?哪些属性可以继承?答:(1)类选择符:id选择符:(2)class属性,伪类a标签,列a表ul,li,dl,dd,dt注:优先级(就近原则):!importa

【Tomcat】面向初级 Web 开发人员的 Tomcat

Apache Tomcat 应用服务器不再是高级 Web 系统开发人员的专用领域.在本教程中,Sing Li 将向初级 Web 开发人员展示如何利用他们当前的 Java™ 开发技能,使用 Tomcat 编写服务器端 JSP.servlet 和 Web 服务. 开始之前 关于本教程 本教程向 Java Web 开发人员介绍使用 Tomcat 对 JavaServer Pages (JSP).servlet 和 Web 服务进行编程,Tomcat 是来自 Apache Foundation 的开源应

FW:考查嵌入式C开发人员的最好的16道题(转)

考查一个初级嵌入式系统开发人员的C基本功,附有答案题目由资深嵌入式系统专家拟定, 目的是考查入门级的嵌入式软件开发人员 Gavin Shaw提供详细解答. 编者按:非常基本关于C语言的问题,一个信息类(计算机,资讯工程,电子工程, 通信工程) 专业的本科毕业生应该达到的水平,如果你有3道以上的题目不能答对,基本上我们都不好 说什么了....题目不难,全部都能快速地答完,当然也需要一定的知识储备. 约定:   1) 下面的测试题中,认为所有必须的头文件都已经正确的包含了    2)数据类型    

产品经理如何赢得开发人员的尊重和支持?-摘自infoq

对于产品经理来说,赢得开发人员的尊重和支持,从某种意义上讲,是产品迈向成功的坚实一步.最近,知乎社区上的开发人员和管理者在前.后两个帖子中对此展开了激烈的讨论,其中不乏真知灼见. 林志霖Cray认为产品经理的决策和行为都应该为项目的目标服务,不要热衷于斗争,团队管理值得注意的几点包括: 了解美术/前端/后端工作原理.     如果你知道美术设计主菜单悬停二级的不规则投影会浪费前端大把的时间调试,你还能想像前端看到了多难过,你就及时建议改用规则统一透明度的投影.如果你知道后端用for循环输出20条

Web开发人员需知的Web缓存知识

什么是Web缓存,为什么要使用它? Web缓存游走于服务器和客户端之间.这个服务器可能是源服务器(资源所驻留的服务器Add),数量可能是1个或多个:这个客户端也可能是1个或多个.Web缓存就在服务器-客户端之间搞监控,监控请求,并且把请求输出的内容(例如html页面. 图片和文件)(统称为副本)另存一份:然后,如果下一个请求是相同的URL,则直接请求保存的副本,而不是再次麻烦源服务器. 使用缓存的2个主要原因: 降低延迟:缓存离客户端更近,因此,从缓存请求内容比从源服务器所用时间更少,呈现速度更

英特尔 Android* 开发人员指南上的对等应用

简介 当没有 Wi-Fi 访问点或互联网访问时,Android* 应用可能需要对等连接在两台或多台 Android* 设备之间建立连接. 比如,文件共享应用和多人游戏. 该功能可使用 NFC.蓝牙或 Wi-Fi 对等技术来实施. 特定案例中的首选技术需要根据所需的距离.连接速度.功耗和独特的技术特性来决定. 本文将对 Wi-Fi 对等技术进行评估. Wi-Fi 对等(P2P)支持具备适当应用的 Android 4.0 或更高版本在没有接入点的情况下通过 Wi-Fi 彼此连接. Android W