Использование CSOM в C# для динамической загрузки столбцов Project Server из выбранных строк
Я использую CSOM .NET для загрузки объектов задач из Project Server 2013, и мне нужно
- фильтровать задачи так, чтобы возвращалось только их подмножество, и
- загрузить только подмножество столбцов задач, указанных пользователем во время выполнения.
Я нашел этот пост, который показывает, как загрузить динамический набор столбцов, и он прекрасно работает для моего второго требования. Тем не менее, я не могу понять работоспособный синтаксис LINQ, чтобы объединить выбор столбцов и фильтрацию строк.
В приведенном ниже примере мне нужно загрузить только эти "строки" для итоговых задач (где t.IsSummary - true), и я хочу загрузить только столбцы Name, Start и Finish.
Следующий код из ссылочного поста загружает только три нужных мне столбца:
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 за пределы цикла над именами полей и сделаю его отдельным вызовом Load, фильтрация строк сводной задачи сработает, но я потеряю динамический выбор полей задач. В LINQ для CSOM должен быть синтаксис, отвечающий обоим требованиям. Каков правильный синтаксис для выполнения этого типа запроса?
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();
Я сам ответил на это, используя деревья выражений, которые позволяют фильтровать набор строк и выбирать набор столбцов на основе параметров, которые известны только во время выполнения. В приведенном ниже примере я симулирую обнаружение во время выполнения того, что мне нужно отфильтровать задачи в столбце IsSummary и что мне нужно получить только пять столбцов Id, Name, Start, IsSubProject и Finish. Вот код:
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 Geek
..Джим