Использование CSOM в C# для динамической загрузки столбцов Project Server из выбранных строк

Я использую CSOM .NET для загрузки объектов задач из Project Server 2013, и мне нужно

  • фильтровать задачи так, чтобы возвращалась только их часть, и
  • загружать только подмножество столбцов задачи, указанное пользователем во время выполнения.

Я нашел этот сообщение, в котором показано, как загрузить динамический набор столбцов. , и это прекрасно работает для моего второго требования. Однако я не могу найти работающий синтаксис LINQ для объединения оба выбора столбца и фильтрации строк.

В приведенном ниже примере мне нужно загрузить только те «строки» для сводных задач (где t.IsSummary равно true), и я хочу загрузить только Столбцы имени, Начало и Конец.

Следующий код из упомянутого поста загружает только три нужных мне столбца:

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

Но когда я пытаюсь объединить where() и include() в единственном синтаксисе, который имеет для меня смысл, я получаю InvalidQueryExpressionException на второй итерации. через цикл foreach: «Выражение запроса не поддерживается».

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

Я получаю ту же ошибку, если я изменяю порядок предложений where и include. Если я вытащу предложение where за пределы цикла по именам полей и сделаю его отдельным вызовом Load, фильтрация строк сводной задачи будет работать, но я потеряю динамический выбор поля задач. В LINQ для CSOM должен быть синтаксис, отвечающий обоим требованиям. Каков правильный синтаксис для выполнения этого типа запроса?


person Jim Black    schedule 04.05.2016    source источник


Ответы (2)


В следующем примере показано, как применять операторы выбора и фильтрации в 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();
person Vadim Gremyachev    schedule 26.05.2016
comment
Спасибо за ответ. Да, CAML решит мою проблему, но нет возможности вызвать CAML с CSOM Project Server. Он работает со списками SharePoint, но не с объектами Project Server, такими как проекты и задачи. Ваша вторая идея будет работать, но она не динамична. Скорее, это жестко запрограммировано для трех полей Имя, Начало и Завершение. Мне нужен метод, который будет включать произвольный список полей; может быть 3 поля или может быть 10 полей. - person Jim Black; 27.05.2016
comment
Более простое объяснение того, что мне нужно: мне нужен способ указать включенные поля во время выполнения, а не во время компиляции. Поэтому я не могу написать код, который специально включает только три поля Name, Start и Finish. Вместо этого мне нужен код, который может включать произвольный список из N полей во время выполнения. Спасибо еще раз! - person Jim Black; 27.05.2016

Я сам ответил на это, используя деревья выражений, которые позволяют фильтровать набор строк и выбирать набор столбцов на основе параметров, которые известны только во время выполнения. В приведенном ниже примере я имитирую обнаружение во время выполнения, что мне нужно отфильтровать задачи в столбце IsSummary и что я должен получить только пять столбцов Id, Имя, Начало, IsSubProject и Завершение. Вот код:

        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 и в Second Life венгерского специалиста по SharePoint

..Джим

person Jim Black    schedule 25.06.2016