Неподдерживаемые запросы LINQ и двухуровневые запросы
Дата последнего изменения: 22 сентября 2011 г.
Применимо к: SharePoint Foundation 2010
В этой статье
Неподдерживаемые запросы
Двухэтапные запросы
Когда различия не имеют значения
В данной статье описываются определенные виды запросов LINQ, которые не поддерживаются поставщиком LINQ для SharePoint. В статье также описывается, как двухэтапный процесс используется для запросов с операторами LINQ, которые не могут быть преобразованы поставщиком LINQ для SharePoint в Collaborative Application Markup Language (CAML).
Неподдерживаемые запросы
Некоторые виды запросов, которые стали доступны в синтаксисе LINQ для C# и Visual Basic и которые хорошо работают в некоторых контекстах для некоторых видов источников данных, приводят к неприемлемо плохой производительности в случае применения к данным веб-сайта Microsoft SharePoint Foundation. Такие запросы не поддерживаются поставщиком LINQ для SharePoint. В частности, это относится к любым запросам, требующим более одного отдельного запроса к базе данных контента. Например если запрос к таблице А требует отдельного запроса к таблице Б для каждой строки таблицы А, то запрос к таблице А не поддерживается. Подобно этому, попытка использования ключевого слова union в LINQ, как показано в следующем примере, не поддерживается и может создать исключение, так как требуются отдельные запросы к двум спискам.
DataContext data = new DataContext("http://ContosoServer"); DataContext juniorData = new DataContext("http://ContosoServer/JuniorTeamSite");
EntityList<Announcement> Announcements = data.GetList<Announcement>("Announcements");
EntityList<Announcement> JuniorAnnouncements = juniorData.GetList<Announcement>("Announcements");
var seniorAnns = from ann in Announcements
select ann;
var juniorAnns = from ann in JuniorAnnouncements
select ann;
IEnumerable<Announcement> mergedAnns = seniorAnns.union(juniorAnns);
foreach (Announcement ann in mergedAnns)
{
Console.WriteLine(ann.Title);
}
Одно следствие этого правила заключается в том, что запросы, которые принимают явное объединение двух списков SharePoint Foundation, поддерживаются только в том случае, когда объединяемое поле настроено в качестве поля просмотра.
Двухэтапные запросы
Некоторые запросы LINQ не могут быть полностью преобразованы в CAML. Однако такие запросы могут работать правильно, если они могут быть выполнены в два этапа. Сначала поставщик LINQ для SharePoint преобразовывает максимально возможную часть запроса в CAML и выполняет ее. Это производит поднабор данных, который передается от базы данных контента обратно в интерфейсный веб-сервер в виде объекта IEnumerable<T>. Затем оставшиеся части запроса преобразуются в запрос LINQ для объектов, адресованный объекту IEnumerable<T>. (Первый этап, однако, должен выполняться за один запрос в базу данных контента. В противном случае весь запрос вызовет исключение.)
Например, оператор LINQ select, такой как "select new { c.Name, c.ZipCode }", является одноэтапным. Этот оператор может быть преобразован в CAML как тег <ViewFields (Возможно, на английском языке)> с двумя дочерними элементами <FieldRef (Возможно, на английском языке)>. Но оператор "select new { c.Price*2, c.Orders, c.Customer }" содержит математическую функцию, которая не поддерживается в CAML. Поэтому запрос преобразуется поставщиком LINQ для SharePoint и выполняется, но только до оператора select. Затем результаты, полученные от запроса CAML, передаются на интерфейсный веб-сервер в виде объекта IEnumerable<T>. Новый запрос LINQ на интерфейсном веб-сервере затем выполняет проекцию оператора select на объект с помощью метода Enumerable.Select() LINQ для объектов.
Нет простого способа для определения операторов LINQ, которые не поддерживаются или требуют двух этапов выполнения. Например, оператор Union(), как замечено выше, не поддерживается, если оба источника данных, которые должны быть объединены, являются списками базы данных контента. Но если только один из них является списком SharePoint Foundation, а другой является, например, таблицей, уже находящейся в памяти, то оператор Union() может использоваться.
В большинстве случаев методы запросов, которые требуют математических операций, требуют двух этапов выполнения, но существуют исключения, когда поставщик LINQ для SharePoint может получить значение от объектной модели SharePoint Foundation. Например, методы Count() и LongCount() не требуют разделения запросов на два этапа.
Следующие операторы обычно требуют два этапа выполнения и обычно работают, если первый этап требует только одного запроса к базе данных контента.
Когда различия не имеют значения
Если в любом случае выходные данные частей запроса, которые могут быть преобразованы в запрос CAML, пишутся в объект IEnumerable<T> (с помощью методов ToList<TSource>(IEnumerable<TSource>), ToDictionary() или ToArray<TSource>(IEnumerable<TSource>)), то часть запроса, которая выполняется после вызова одного из этих методов, использует операторы запроса из класса Enumerable, а не из класса Queryable. В этом случае различие между двухэтапными и одноэтапными запросами не имеет значения.
Например, сравните следующие два запроса. Оба требуют двухэтапного выполнения, так как используется математический оператор "-"; но второй запрос делает это явно, так как поставщик LINQ для SharePoint используется только в строке from, которая читает весь список "orders" (заказы) в элемент IList<T>.
var ordersInArrears = from order in orders
where order.Price – order.Paid > 0
select order;
var ordersInArrears = from order in orders.ToList()
where order.Price – order.Paid > 0
select order;
Разделение запросов на части LINQ для SharePoint и LINQ для объектов вручную может также позволить использование ключевых слов LINQ, которые в другом случае могут не поддерживаться. Например, следующая версия объединения двух наборов извещений должна работать, так как запросы LINQ для SharePoint перечислены отдельно в двух объектах IEnumerable<T>. Используемое ключевое слово union является версией LINQ для объектов Union().
DataContext data = new DataContext("http://ContosoServer"); DataContext juniorData = new DataContext("http://ContosoServer/JuniorTeamSite");
EntityList<Announcement> Announcements = data.GetList<Announcement>("Announcements");
EntityList<Announcement> JuniorAnnouncements = juniorData.GetList<Announcement>("Announcements");
List<Announcement> seniorAnns = (from ann in Announcement
select ann).ToList();
List<Announcement> juniorAnns = (from ann in JuniorAnnouncements
select ann).ToList();
IEnumerable<Announcement> mergedAnns = seniorAnns.union(juniorAnns);
foreach (Announcement ann in mergedAnns)
{
Console.WriteLine(ann.Title);
}
См. также
Ссылка
Select