【问题标题】:Get result from function in batches批量获取函数结果
【发布时间】:2019-07-10 10:34:33
【问题描述】:

我有一个函数可以从 SharePoint 列表中获取 x 个数字 og 项目。它分批接收项目。在每批之后,我对这些项目做一些事情,销毁所有东西并计算下一批。我目前考虑使用事件。所以每批都有一个活动。这是正确的策略还是有更好的方法?我在考虑匿名函数或类似的东西?

    public static List<Item> GetAllItems(this List list, int rowLimit, List<string> fields, bool includeRoleAssignments, ILogger logger)
    {
        var result = new List<Item>();
        var ctx = list.Context;

        ListItemCollectionPosition position = null;
        var camlQuery = new CamlQuery();
        camlQuery.ViewXml =
        @"<View Scope='RecursiveAll'>
            <Query>
                <OrderBy Override='TRUE'><FieldRef Name='ID'/></OrderBy>
            </Query>
            <ViewFields></ViewFields>" +
            "<RowLimit Paged='TRUE'>" + rowLimit + "</RowLimit>" +
        "</View>";

        System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

        do
        {
            try
            {
                using (var clonedCtx = ctx.Clone(ctx.Url))
                {
                    List listWithClonedContext = clonedCtx.Web.Lists.GetByTitle(list.Title);
                    clonedCtx.Load(listWithClonedContext);
                    clonedCtx.ExecuteQuery();

                    ListItemCollection listItems = null;
                    camlQuery.ListItemCollectionPosition = position;
                    listItems = listWithClonedContext.GetItems(camlQuery);


                    foreach (string field in fields)
                    {
                        clonedCtx.Load(listItems, includes => includes.Include(i => i[field]));
                    }

                    if (!includeRoleAssignments) { 
                        clonedCtx.Load(listItems, item => item.ListItemCollectionPosition);
                    }
                    else { 
                        clonedCtx.Load(listItems, item =>
                        item.ListItemCollectionPosition,
                        item => item.Include(                       
                            i => i.RoleAssignments.Include(
                                ra => ra.Member,
                                ra => ra.Member.LoginName,
                                ra => ra.RoleDefinitionBindings.Include(rd => rd.Description, rd => rd.Name))));
                    }

                    clonedCtx.Load(listItems, item => item.ListItemCollectionPosition);
                    clonedCtx.ExecuteQueryWithIncrementalRetry(3, 1, logger);


                    // here i want to do something with items before next loop/batch

                    position = listItems.ListItemCollectionPosition;

                    if (position != null)
                    {
                        logger.WriteTrace(string.Format("Iteration on getting items performed: {0}", position.PagingInfo), SeverityLevel.Verbose);
                    }
                    else
                    {
                        logger.WriteTrace("Getting all items finished.", SeverityLevel.Verbose);
                    }
                    logger.Flush();
                }
            }
            catch (Exception ex)
            {
                logger.WriteException(ex);
            }
        }
        while (position != null);
        return result;
    }

【问题讨论】:

  • 我知道。我想重构它以返回批次。那就是我的问题。对于这种模式,您通常会使用 yield、events 还是其他东西?
  • 刚试了产量。似乎它是我正在寻找的方法。你能补充一个答案。感谢您的帮助。
  • 您希望这些活动做什么?为什么要举办活动?
  • @Enigmativity 说实话我想使用事件,因为我不知道收益模式:D 那是唯一的原因。收益是要走的路。

标签: c# yield-return


【解决方案1】:

也许事件是一种选择,但也可能有一种更简单的方法可以将它们“流式传输”出来,而不是通过列表一次全部返回。因此使用yield 并更改为IEnumerable&lt;Item&gt;

public static IEnumerable<Item> EnumerateItems(this List list, int rowLimit, List<string> fields, bool includeRoleAssignments, ILogger logger)
{
    // ...
    do
    {
        try
        {
            using (var clonedCtx = ctx.Clone(ctx.Url))
            {
                //...
                camlQuery.ListItemCollectionPosition = position;
                listItems = listWithClonedContext.GetItems(camlQuery);
                // ...
                foreach(Item x in listItems)
                {
                    yield return x;
                }
                position = listItems.ListItemCollectionPosition;
                // ...
    }
    while (position != null);
}

通过这种方式,您可以在仍在获取它们的同时开始处理它们,或者您可以过滤它们,例如使用WhereSkipTake,而无需先将所有内容加载到内存中。

【讨论】:

  • 我什至不知道 yield 是一个关键字!积极的。
猜你喜欢
  • 2015-10-15
  • 2021-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 2016-02-27
  • 1970-01-01
  • 2011-03-03
相关资源
最近更新 更多