Как получить только уникальные значения полей из запроса SharePoint CSOM?

Я использую клиентскую объектную модель SharePoint для извлечения данных из списка SharePoint 2013. Следующий код работает и получает все значения из поля списка keyCol, правильно отсортированные:

string keyCol = "SPFieldName";
CamlQuery keyColumnValuesQuery = CamlQuery.CreateAllItemsQuery();
ListItemCollection keyColumnValues = srcDocLib.GetItems(keyColumnValuesQuery);
spContext.Load(keyColumnValues, items => items.Include(item => item[keyCol]), items => items.OrderBy(item => item[keyCol]));
spContext.ExecuteQuery();

Однако я хотел бы получить только один элемент для каждого уникального значения в поле, отличительного. Когда я добавляю Distinct() Linq/Lambda в аргумент извлечения метода Load (нет проблем со временем компиляции):

spContext.Load(keyColumnValues, items => items.Include(item => item[keyCol]), items => items.OrderBy(item => item[keyCol]), items => items.Distinct());

Я получаю InvalidQueryExpressionException: выражение запроса 'items.Distinct()' не поддерживается.

Означает ли это, что поставщик Linq на стороне SharePoint не поддерживает это выражение, и мне просто не повезло с использованием этой техники? Я что-то делаю неправильно? Спасибо.


person user640118    schedule 21.03.2014    source источник


Ответы (1)


Поставщик Linq для SharePoint не поддерживает оператор Distinct.

Согласно MSDN:

Некоторые запросы LINQ невозможно полностью преобразовать в CAML. Однако такие запросы, в принципе, могут выполняться корректно, поскольку могут выполняться в два этапа. Во-первых, поставщик LINQ to SharePoint переводит как можно большую часть запроса в CAML и выполняет этот запрос.

См. неподдерживаемые запросы LINQ и двухэтапные Запросы для более подробной информации.

Двухэтапный подход

Чтобы исправить эту ошибку, вы должны разделить свои запросы на два этапа, чтобы принудительно выполнить первый запрос перед вторым. Для этого вы должны, например, преобразовать первый IEnumerable<T> в списке с помощью метода ToList().

В следующем примере показано, как вернуть уникальные значения:

   //1 Execute query against SP Linq provider   
    string keyCol = "SPFieldName";
    CamlQuery keyColumnValuesQuery = CamlQuery.CreateAllItemsQuery();
    ListItemCollection keyColumnValues = srcDocLib.GetItems(keyColumnValuesQuery);
    spContext.Load(keyColumnValues, items => items.Include(item => item[keyCol]), items => items.OrderBy(item => item[keyCol]));
    spContext.ExecuteQuery();
    //2. Transform LiItemCollection to a List and perform Distinct operation 
    var uniqueKeyColumnValues = keyColumnValues.ToList().Select(i => i[keyCol]).Distinct(); 
person Vadim Gremyachev    schedule 22.03.2014
comment
Спасибо, это работает, и это то, что я искал. Пара дополнительных вопросов для моего понимания, если вы не возражаете. На первый взгляд я подумал, что uniqueKeyColumnValues ​​будет иметь тип List‹ListItem›, но оказалось, что это тип List‹string› (фактически предпочтительнее для меня). Извлекает ли часть вашего кода Select строковое значение из поля ListItem вместо всего поля ListItem? - person user640118; 25.03.2014
comment
В какой-то момент я попробовал keyColumnValues.ToList().Distinct(), но получил тот же результат с дубликатами. Это потому, что я дал ему только один список для различения, а не ряд значений, и с этой точки зрения список, который он мне вернул, был действительно отличным? - person user640118; 25.03.2014
comment
Правильно, выберите оператор извлечения значений полей. Например, если поле типа Text, то запрос вернет List ‹string› - person Vadim Gremyachev; 25.03.2014