首页 > 解决方案 > 我应该使用一个或多个 ClientContext 来更新一个非常大的列表吗?

问题描述

我需要更新一个大型 SharePoint 列表,大约 10,000 项或更多。每个 ListItem 有 4 列要更新。我不知道这种情况下最好的方法是什么:

  1. 使用 1 个 ClientContext,以 n 行的批次获取 ListItemCollection,遍历每个 ListItem 并在下一批之前更新其列。或者
  2. 以 n 行的批次获取 ListItemCollectionPosition 列表,遍历每个 ListItemCollectionPosition,创建新的 ClientContext,获取 ListItemCollection 然后更新。

方法一

using (ClientContext ctx = new ClientContext(url))
{
   ctx.Credentials = new SharePointOnlineCredentials(username,password);
   List list = ctx.Web.Lists.GetByTitle("mylist");
   ctx.Load(list);
   ctx.ExecuteQuery();
   ListItemCollectionPosition pos = null;
   CamlQuery camlQuery = new CamlQuery
   {
       ViewXml = "<View Scope='Recursive'><RowLimit>100</RowLimit></View>"
   };
   do           
   {
        if (pos != null)
        {
            camlQuery.ListItemCollectionPosition = pos;
        }
        ListItemCollection listItemCollection = list.GetItems(camlQuery);
        ctx.Load(listItemCollection);
        ctx.ExecuteQuery();
        pos = listItemCollection.ListItemCollectionPosition;
        foreach(ListItem item in listItemCollection)
        {
            item["col1"] = "abc";
            item["col2"] = "def";
            item["col3"] = "ghi";
            item["col4"] = "jkl";
            item.Update();
        }
        ctx.ExecuteQuery();
    } while (pos != null);
}

方法二

private void UpdateList()
{
   using (ClientContext ctx = new ClientContext(url))
   {
       ctx.Credentials = new SharePointOnlineCredentials(username,password);
       List list = ctx.Web.Lists.GetByTitle("mylist");
       ctx.Load(list);
       ctx.ExecuteQuery();
       ListItemCollectionPosition pos = null;
       CamlQuery camlQuery = new CamlQuery
       {
           ViewXml = "<View Scope='Recursive'><RowLimit>100</RowLimit></View>"
       };
       List<ListItemCollectionPosition> positions = new List<ListItemCollectionPosition>();
       do           
       {
           if (pos != null)
           {
               camlQuery.ListItemCollectionPosition = pos;
           }
           ListItemCollection listItemCollection = list.GetItems(camlQuery);
           ctx.Load(listItemCollection);
           ctx.ExecuteQuery();
           pos = listItemCollection.ListItemCollectionPosition;
           positions.Add(pos);            
       } while (pos != null);
       List<Task> tasks = new List<Task>();
       foreach(var position in positions)
       {
           tasks.Add(UpdateItem(position));
       }
       Task.WaitAll(tasks.ToArray());
    }
}
private Task UpdateItem(ListItemCollectionPosition pos)
{
   using (ClientContext ctx = new ClientContext(url))
   {
      ctx.Credentials = new SharePointOnlineCredentials(username,password);
      List list = ctx.Web.Lists.GetByTitle("mylist");
      ctx.Load(list);
      ctx.ExecuteQuery();
      CamlQuery camlQuery = new CamlQuery
      {
          ViewXml = "<View Scope='Recursive'><RowLimit>100</RowLimit></View>"
      };
      camlQuery.ListItemCollectionPosition = pos;
      ListItemCollection listItemCollection = list.GetItems(camlQuery);
      ctx.Load(listItemCollection);
      ctx.ExecuteQuery();
      foreach(ListItem item in listItemCollection)
      {
           item["col1"] = "abc";
           item["col2"] = "def";
           item["col3"] = "ghi";
           item["col4"] = "jkl";
           item.Update();
      }
      return ctx.ExecuteQueryAsync();
    }
}

标签: c#sharepoint-onlinelistitemcsom

解决方案


在方法 1 和 2 中,我将 ViewFields 设置为限制传输的数据量。

在方法 2UpdateItem中,方法在positions收集满后执行。为什么positions在填充集合时不更新列表项 - 您可以使用 yield 属性实现枚举器。

public static IEnumerable<ListItemCollectionPosition> GetPositions()
{            
     do           
     {
       ...
       yield return pos;
       ...
     } while (pos != null);
}

推荐阅读