Мифы и правда о 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
Очередной миф разрушен, идем дальше.
Миф 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 - не ваш подход. В остальных случаях я советую использовать именно его.