如何使用CSOM在Sharepoint 2013中递归更改ListItems的值

时间:2016-01-18 14:41:22

标签: c# sharepoint-2013 csom

我的情况

您好, 我的客户端有一个Sharepoint Server 2013 on Premise。他想在多个文件上编写元数据。更具体地说,他想要选择一个文件夹,然后应用程序应该为该文件夹中的每个文件/文件夹的列中写入相同的值。

我已经做了什么

我写了一个CAML查询,它返回所选文件夹下面的所有文件/文件夹。然后我写下每个项目的值并更新它。

我想做什么

我想编写一个应用程序,我的客户端可以选择一个文件夹。之后,软件应该更新该文件夹下的所有文件。 我想用C#和CSOM编写这个应用程序。

我的问题

这很慢。每个文件夹有数千个文件,只需要几个小时就可以完成一个文件夹。

我的问题

有没有办法加快速度?
CAML-Query是否也可以更新值?
做我想做的事情的推荐方法是什么? 是否有其他方法可以实现客户的需求?

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

您可以利用名为Request Batching的功能,这可以通过最大限度地减少客户端和服务器之间传递的消息数

来显着影响性能。

来自documentation

  

CSOM编程模型是围绕请求批处理构建的。当你   使用CSOM,您可以执行一系列数据操作   ClientContext对象。这些操作将提交给服务器   致电ClientContext.BeginExecuteQuery时的一个请求   方法

为了进行比较,我们演示了两种更新多个列表项的方法:

标准方式:

foreach (var item in items)
{
   item["LastReviewed"] = DateTime.Now;
   item.Update();
   ctx.ExecuteQuery();
}

批量更新:

foreach (var item in items)
{
   item["LastReviewed"] = DateTime.Now;
   item.Update();
}
ctx.ExecuteQuery();
  

注意:在第二种方法中,只有一个批处理请求   提交到服务器

完整示例

var listTitle = "Documents";
var folderUrl = "Archive/2013";

using (var ctx = GetContext(url, userName, password))
{
     //1. Get list items operation
     var list = ctx.Web.Lists.GetByTitle(listTitle);
     var items = list.GetListItems(folderUrl);
     ctx.Load(items);
     ctx.ExecuteQuery();


     //2. Update list items operation
     var watch = Stopwatch.StartNew();
     foreach (var item in items)
     {
           if(Convert.ToInt32(item["FSObjType"]) == 1) //skip folders
               continue;

           item["LastReviewed"] = DateTime.Now;
           item.Update();
           //ctx.ExecuteQuery();
           Console.WriteLine("{0} has been updated", item["FileRef"]);
     }
     ctx.ExecuteQuery();  //execute batched request
     watch.Stop();
     Console.WriteLine("Update operation completed: {0}", watch.ElapsedMilliseconds); 

     Console.ReadLine();
}

其中GetListItems是获取位于特定文件夹下的列表项的扩展方法:

using System.Linq;
using Microsoft.SharePoint.Client;

namespace SharePoint.Client.Extensions
{
    public static class ListCollectionExtensions
    {

        /// <summary>
        /// Get list items located under specific folder 
        /// </summary>
        /// <param name="list"></param>
        /// <param name="relativeFolderUrl"></param>
        /// <returns></returns>
        public static ListItemCollection GetListItems(this List list, string relativeFolderUrl)
        {
            var ctx = list.Context;
            if (!list.IsPropertyAvailable("RootFolder"))
            {
                ctx.Load(list.RootFolder, f => f.ServerRelativeUrl);
                ctx.ExecuteQuery();
            }
            var folderUrl = list.RootFolder.ServerRelativeUrl + "/" + relativeFolderUrl;
            var qry = CamlQuery.CreateAllItemsQuery();
            qry.FolderServerRelativeUrl = folderUrl;
            var items = list.GetItems(qry);
            return items;
        }
    }
}