Должен ли я использовать один или несколько ClientContext для обновления очень большого списка?

Мне нужно обновить большой список SharePoint, около 10 000 или более элементов. Каждый ListItem имеет 4 столбца для обновления. Я не знаю, что лучше всего подходит для этого сценария:

  1. Используйте 1 ClientContext, выберите ListItemCollection в пакете из n строк, переберите каждый ListItem и обновите его столбцы перед следующим пакетом. Или
  2. Получите список ListItemCollectionPosition в пакете из n строк, пройдитесь по каждому ListItemCollectionPosition, создайте новый ClientContext, выберите ListItemCollection и затем обновите.

Способ 1

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);
}

Способ 2

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();
    }
}

person Jack Le    schedule 14.03.2019    source источник


Ответы (1)


В методах 1 и 2 я бы установил ViewFields, чтобы ограничить объем передаваемых данных.

В методе 2 метод UpdateItem выполняется после заполнения positions коллекции. Почему бы не обновить элементы списка во время заполнения коллекции positions - вы можете реализовать перечислитель с атрибутом yield.

public static IEnumerable<ListItemCollectionPosition> GetPositions()
{            
     do           
     {
       ...
       yield return pos;
       ...
     } while (pos != null);
}
person Rafał Milewski    schedule 19.08.2019