Мифы и правда о Linq to SharePoint

Миф 1. Linq to SharePoint работает медленно

Это стандартная мулька про Linq to SharePoint. Логика здесь следующая: Linq to SharePoint - это "обертка" поверх CAML-запросов, следовательно он работает медленнее, чем заранее сформированный CAML-запрос. Вот только здесь есть два нюанса:

Во-первых, заранее сформированный CAML-запрос - это вариант мало применимый в реальных приложениях, он хорош для примеров: заранее заточенные требования, не препятствующие ограничениям и минимум функциональности, с целью "сфокусироваться на сути".

Во-вторых, результат, получаемый нативными средствами SharePoint - это объект SPListItem, который надо еще преобразовать в применимый для бизнес-приложений объект. Элементарная задача, когда надо добавить вычисляемое поле, например, булево поле, которое отвечает за признак того, что объект последний раз изменялся более месяца назад в правильной бизнес-сущности выглядит вот так:

public bool IsOld
{
    get
    {
        //ModifiedDate - свойство типа DateTime
        return (DateTime.Today - ModifiedDate).TotalDays;
    }
}

Аналог в нативной среде SPListItem будет выглядеть гораздо страшнее: придется либо создавать вычисляемое поле, либо писать кучу кода, выбирая нужные свойства, приводя их к нужному типу и сравнивая значения.

В случае с SPListItem этот элементарный трюк не пройдет. Для придания коду читабельности и правильности придется мапить его на бизнес-объект. И в этом случае Linq to SharePoint - лучшая технология доступа к данным в Sharepoint 2010/2013. В сравнении с Camlex.NET Linq to SharePoint намного быстрее. Подробнее можно почитать мой пост Linq to SharePoint. Сравнение производительности с Camlex.NET.

Миф 2. Linq to SharePoint не поддерживает локализацию

При использовании SPMetal код, который им сгенерирован для объекта, описывающего тип содержимого имеет следующий вид:

[ContentType(
    Id = "0x01", //ID типа содержимого 
    List = "Название списка", 
    Name = "Название типа содержимого")]
public class ListItem : ITrackEntityState, ITrackOriginalValues, 
    INotifyPropertyChanged, INotifyPropertyChanging
{
    // bla-bla
}

Конечно в таком представлении нельзя локализовать параметры атрибута: локализации в нем не реализована и унаследоваться от него, усложнив логику, тоже нельзя - он запечатанный (sealed). И тут начинается паника.

А решение данной проблемы крайне тривиально - просто не указывать значения свойств Name и List в атрибуте. Вот такой вариант будет работать ровно также:

[ContentType(Id = "0x01")]
public class ListItem : ITrackEntityState, ITrackOriginalValues, 
    INotifyPropertyChanged, INotifyPropertyChanging
{
    // bla-bla
}

Что касается метода DataContext.GetList и обертки для него, которую генерирует SPMetal, то здесь уже можно вдоволь порезвиться и выдернуть имя списка хоть из ресурсов, хоть по его идентификатору, хоть по URL'у.

Очередной миф разрушен, идем дальше.

Миф 3. Linq to SharePoint всегда фильтрует данные по типу содержимого

Последний на сегодня миф, связанный с тем, что для каждого типа содержимого создается отдельный класс и выборка данных из списка основана на получении коллекции этих объектов. И так как в одном списке SharePoint могут находится данные разных типов, то при выборке присутствует фильтрация по типу содержимого. На форумах частенько на это жалуются и указание в качестве типа контента общего родительского (например, 0x01) не помогает.

Для примера я создал список в SharePoint, содержащем два типа содержимого: Элемент и Контакт. С демонстрационными данными:

Стандартный запрос будет выглядеть примерно так:

<View>
    <Query>
        <Where>
            <BeginsWith>
                <FieldRef Name="ContentTypeId" />
                <Value Type="ContentTypeId">0x01</Value>
            </BeginsWith>
        </Where>
    </Query>
    <ViewFields>
        <FieldRef Name="ID" />
        <FieldRef Name="owshiddenversion" />
        <FieldRef Name="FileDirRef" />
        <FieldRef Name="Title" />
        <FieldRef Name="Author" />
        <FieldRef Name="FirstName" />
        <FieldRef Name="FullName" />
        <FieldRef Name="ContentType" />
    </ViewFields>
    <RowLimit Paged="TRUE">2147483647</RowLimit>
</View>

И проблема появляется сама собой: как убрать фильтр по типу содержимого? Очень просто. Чтобы за один запрос к списку получить все данные, содержащиеся в нем, надо просто удалить атрибут ContentType из класса. Тогда запрос сразу превращается примерно в такой:

<View>
    <Query></Query>
    <ViewFields>
        <FieldRef Name="ID" />
        <FieldRef Name="owshiddenversion" />
        <FieldRef Name="FileDirRef" />
        <FieldRef Name="Title" />
        <FieldRef Name="Author" />
        <FieldRef Name="FirstName" />
        <FieldRef Name="FullName" />
        <FieldRef Name="ContentType" />
    </ViewFields>
    <RowLimit Paged="TRUE">2147483647</RowLimit>
</View>

Для типов содержимого, которые не имеют свойств, подлежащих выборке из списка/библиотеки документов, данные свойства будут иметь значения null.

Последний на сегодня миф разрушен. Переходим к жестокой правде.

Правда 1. Linq to SharePoint не умеет обрабатывать членство пользователя в группе

Запросы на проверку вхождения пользователя в группу, указанную в свойстве элемента списка Linq to SharePoint строить не умеет. Какие это запросы и примеры их использования можно прочитать в посте Игоря Акимова CAML-запросы с расширенной фильтрацией по пользователям и группам.

Правда 2. Linq to SharePoint не работает со всеми типами полей

Такие типы полей как: метаданные, рейтинг и прочие, появившиеся относительно недавно (SharePoint 2010/2013) не подвластны Linq to SharePoint. В этом случае его возможности ограничиваются на проверку равенства/неравенства null. В более сложных случаях придется загружать данные в память и использовать Linq to Objects.

Правда 3. Linq to SharePoint не умеет разбивать результаты на страницы

К чести Linq to SharePoint стоит обратить внимание та то, что и нативный механизм разбиения результатов на страницы далек от совершенства. За примерами опять же идем на блог Игоря Акимова и читаем пост Разбиение запроса SPQuery на страницы. Решение здесь простое - строить такие запросы, чтобы пользователь не уходил дальше 2-3 страницы.

Зачем нужен Linq to SharePoint?

Linq to SharePoint незаменим при построении решений, которые используются данные в списках/библиотеках вместо внешних баз данных. Ровно как и другие Linq-провайдеры. Если данные хранятся в SQL используйте EntityFramework ~~или Linq to SQL~~, если данные в списках/библиотеках SharePoint, то используйте Linq to SharePoint. Но если ваше решение основано на таксономии или поиске, то Linq to SharePoint - не ваш подход. В остальных случаях я советую использовать именно его.

Виталий Жуков

Виталий Жуков

SharePoint архитектор, разработчик, тренер, Microsoft MVP (Office Development). Более 15 лет опыта работы с SharePoint, Dynamics CRM, Office 365, и другими продуктами и сервисами Microsoft.

Смотрите также

Развертывание списков и библиотек с помощью SPFx-решений

Развертывание списков и библиотек с помощью SPFx-решений

SharePoint. Drag-and-Drop Загрузчик файлов

SharePoint. Drag-and-Drop Загрузчик файлов

CSOM. Загрузка файлов

CSOM. Загрузка файлов

SharePoint List REST API. Часть 2

SharePoint List REST API. Часть 2

SharePoint Framework. Создание веб-части на Angular

SharePoint Framework. Создание веб-части на Angular

SharePoint List REST API. Часть 1

SharePoint List REST API. Часть 1

Презентация с доклада о SharePoint Framework

Презентация с доклада о SharePoint Framework

SharePoint Framework. Создаем AngularJS 1.x Client WebPart

SharePoint Framework. Создаем AngularJS 1.x Client WebPart

SharePoint. Регистрация CSS и JavaScript с помощью DelegateControl

SharePoint. Регистрация CSS и JavaScript с помощью DelegateControl

SharePoint. Расширяем REST API

SharePoint. Расширяем REST API

SharePoint Excel Services. Создаем кредитный калькулятор

SharePoint Excel Services. Создаем кредитный калькулятор

SharePoint Ribbon API. Использование ToggleButton

SharePoint Ribbon API. Использование ToggleButton

SharePoint 2013. How To: настройка входящей почты для разработчиков

SharePoint 2013. How To: настройка входящей почты для разработчиков

5 особенностей SPSiteDataQuery

5 особенностей SPSiteDataQuery

SharePoint 2013. Введение в SharePoint App. Часть 2

SharePoint 2013. Введение в SharePoint App. Часть 2

SharePoint 2013. Введение в SharePoint App. Часть 1

SharePoint 2013. Введение в SharePoint App. Часть 1

Превью для веб-части в SharePoint 2010/2013

Превью для веб-части в SharePoint 2010/2013

SharePoint 2013. Еще немного о новых контролах

SharePoint 2013. Еще немного о новых контролах

SharePoint 2013. Контрол ClientPeoplePicker

SharePoint 2013. Контрол ClientPeoplePicker

SharePoint 2013. Контрол ImageCrop

SharePoint 2013. Контрол ImageCrop

SharePoint 2013. Тип поля Geolocation

SharePoint 2013. Тип поля Geolocation

Создание типа поля в SharePoint

Создание типа поля в SharePoint

SharePoint 2010. Длительные операции с обновляемым статусом

SharePoint 2010. Длительные операции с обновляемым статусом

Linq to SharePoint. Создаем ContentIterator

Linq to SharePoint. Создаем ContentIterator

Linq to SharePoint. Получение данных из другой коллекции сайтов

Linq to SharePoint. Получение данных из другой коллекции сайтов

Linq to SharePoint. Версионность

Linq to SharePoint. Версионность

SharePoint. Получение URL-адреса иконки для документа

SharePoint. Получение URL-адреса иконки для документа

SharePoint 2010. PostBack для Fluent Ribbon API

SharePoint 2010. PostBack для Fluent Ribbon API

Linq to SharePoint. Блокировка документов

Linq to SharePoint. Блокировка документов

Linq to SharePoint. Паттерн Repository

Linq to SharePoint. Паттерн Repository

Linq to SharePoint. Получение мета-данных списка

Linq to SharePoint. Получение мета-данных списка

Linq to SharePoint. Мапинг полей

Linq to SharePoint. Мапинг полей

Linq to SharePoint. Формирование данных для ProcessBatchData

Linq to SharePoint. Формирование данных для ProcessBatchData

Linq to SharePoint. Сравнение производительности с Camlex.NET

Linq to SharePoint. Сравнение производительности с Camlex.NET

Linq to SharePoint. Часть 5. Поля Choice и MultiChoice

Linq to SharePoint. Часть 5. Поля Choice и MultiChoice

Linq to SharePoint. Часть 4. Dynamic LINQ

Linq to SharePoint. Часть 4. Dynamic LINQ

Linq to SharePoint. Особенности. Часть 3

Linq to SharePoint. Особенности. Часть 3

Linq to SharePoint. Особенности. Часть 2

Linq to SharePoint. Особенности. Часть 2

SharePoint 2010. PeopleEditor. Установка значения

SharePoint 2010. PeopleEditor. Установка значения

SharePoint 2010. Настройка входящей почты для кастомного списка

SharePoint 2010. Настройка входящей почты для кастомного списка

Linq to Sharepoint. Особенности

Linq to Sharepoint. Особенности

EntityFramework. Оптимистические блокировки

EntityFramework. Оптимистические блокировки