0

我使用 CSOM .NET 从 Project Server 2013 加载任务对象,我需要

  • 过滤任务,以便只返回其中的一个子集,并且
  • 仅加载用户在运行时指定的任务列的子集。

我发现这篇文章展示了如何加载一组动态列,它很好地满足了我的第二个要求。但是,我想不出一个可行的 LINQ 语法来结合选择和行过滤。

在下面的示例中,我只需要为摘要任务加载那些“行”(其中t.IsSummarytrue),并且我只想加载NameStartFinish列。

引用帖子中的以下代码仅加载我需要的三列:

foreach (string fieldName in new List<string>(){"Name","Start","Finish"});
{
  ctx.Load(ctx.Tasks,c => c.Include(t => t[fieldName]));
}
ctx.ExecuteQuery();  

但是,当我尝试将where()include()组合成唯一对我有意义的语法时,我在通过 foreach 循环进行第二次迭代时得到InvalidQueryExpressionException:“不支持查询表达式。”

foreach (string fieldName in new List<string>(){"Name","Start","Finish"});
{
    ctx.Load(ctx.Tasks,
    c => c.Where(t => t.IsSummary),
    c => c.Include(t => t[fieldName])
    );
}

ctx.ExecuteQuery();

如果我颠倒whereinclude子句的顺序,我会得到同样的错误。如果我将where子句拉到字段名称的循环之外并使其成为单独的Load调用,则摘要任务行过滤有效,但我失去了任务字段的动态选择。CSOM 的 LINQ 中必须有满足这两个要求的语法。执行此类查询的正确语法是什么?

4

2 回答 2

0

以下示例演示了如何在 SharePoint CSOM API 中应用选择和筛选运算符:

var list = ctx.Web.Lists.GetByTitle(listTitle);
var items = list.GetItems(CamlQuery.CreateAllItemsQuery());

var result = ctx.LoadQuery(items.Where(i => (bool)i["IsSummary"]).Include(i => i["Name"], i => i["Start"], i => i["Finish"]));
ctx.ExecuteQuery();

foreach (var item in result)
{
    Console.WriteLine(item["Name"]);    
}

所以,我相信 Project Server CSOM API 支持以下表达式:

var result = ctx.LoadQuery(ctx.Tasks.Where(t => (bool)t["IsSummary"]).Include(t => i["Name"], t => t["Start"], t => t["Finish"]));
ctx.ExecuteQuery();
于 2016-05-26T11:22:59.423 回答
0

我自己通过使用表达式树来回答这个问题,它允许您过滤一组行并根据仅在运行时知道的参数选择一组列。在下面的示例中,我模拟了在运行时发现我需要过滤IsSummary列上的任务,并且我应该只检索IdNameStartIsSubProjectFinish这五个列。这是代码:

        using System.Linq.Expressions;

        // Input parms discovered at runtime
        string filterColumnName = "IsSummary";
        List<string> columnNames = new List<string>(
          new[] { "Id", "Name", "Start", "IsSubProject", "Finish" });

        //  Get the client object for the Published Project matching projGuid
        ctx.Load(ctx.Projects, c => c.Where(p => p.Id == projGuid));
        ctx.ExecuteQuery();
        PublishedProject proj = ctx.Projects.Single();

        // Compute the expression tree for filtering the task rows
        var taskParm = Expression.Parameter(typeof(PublishedTask), "t");
        var predicate = Expression.PropertyOrField(taskParm, filterColumnName);
        var filterExpression = Expression.Lambda<
                Func<PublishedTask, bool>>(predicate, taskParm);

        //  Dynamically generate expression tree for each column to be included
        var colSelectionList = new List<Expression<
                Func<PublishedTask, object>>>();

        foreach (var colName in columnNames)
        {
            var fldExpr = Expression.PropertyOrField(taskParm, colName);
            var fldAsObjExpr = Expression.Convert(fldExpr, typeof(object));
            var colSelectorExpr = Expression.Lambda<
                 Func<PublishedTask, object>>(fldAsObjExpr, taskParm);
            colSelectionList.Add(colSelectorExpr);
        }

        //  Create query using LoadQuery (Load does not work here)                  
        var taskList = ctx.LoadQuery(proj.Tasks
                        .Where(filterExpression)
                        .Include(colSelectionList.ToArray())
                        );

        //  Execute the query
        ctx.ExecuteQuery();
        // taskList now contains just the filtered rows and selected columns

我希望这可以帮助那些坚持使用 CSOM 为 Project Server 执行此操作的其他人。我发现这两个参考资料很有帮助: 在 MSDN匈牙利 SharePoint Geek 的第二人生

..吉姆

于 2016-06-25T23:01:09.660 回答