#c# #sharepoint-online #listitem #csom
#c# #sharepoint-online #listitem #csom
Вопрос:
Мне нужно обновить большой список SharePoint, около 10 000 элементов или более. Каждый элемент списка содержит 4 столбца, которые необходимо обновить. Я не знаю, какой наилучший подход для этого сценария:
- Используйте 1 ClientContext, извлеките ListItemCollection в пакете из n строк, выполните цикл по каждому ListItem и обновите его столбцы перед следующим пакетом. Или
- Извлеките список 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();
}
}
Ответ №1:
В способах 1 и 2 я бы установил ViewFields для ограничения объема передаваемых данных.
В методе 2 UpdateItem
метод выполняется после того, positions
как коллекция заполнена. Почему бы не обновлять элементы списка во время заполнения positions
коллекции — Вы могли бы реализовать enumerator с атрибутом yield.
public static IEnumerable<ListItemCollectionPosition> GetPositions()
{
do
{
...
yield return pos;
...
} while (pos != null);
}