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

Часть 1. First()/FirstOrDefault(), T-SQL IN, Path
Часть 2. Count(), Take(), Skip(), JOIN
Часть 3. Анонимный доступ, Получение списка по URL'у, Cross-Site запросы
Часть 4. SPListItem -> LINQ, Dynamic Linq to SharePoint
Часть 5. Поля Choice и MultiChoice в Linq to SharePoint
Часть 6. Сравнение производительности Linq to SharePoint и Camlex.NET

В SharePoint 2010 появилась замечательная вещь под названием Linq-to-SharePoint. Не без особенностей конечно. Вот некоторые из тех, что я "нашел".

1. First() / FirstOrDefault()

Те, кто работал с Linq-to-SQL или Entity Framework, знают, что запрос вида:

using (var ctx = new HRDataContext(webUrl))
{
  var emps = ctx.EmployeeCollection.First(e => e.Id == id);
}

равнозначен запросу:

using (var ctx = new HRDataContext(webUrl))
{
  var emps = ctx.EmployeeCollection.Where(e => e.Id == id).First();
}

Вот только это не работает в SharePoint'е. Там этот запрос равнозначен следующему:

using (var ctx = new HRDataContext(webUrl))
{
  var emps = ctx.EmployeeCollection.ToList().Where(e => e.Id == id).First();
}

Если тестировать приложение на 10-20 записях в списке, то можно не заметить падения производительности. Такая бага может проявить себя далеко после сдачи решения заказчику.

Вывод
не использовать .First() без предварительной фильтрации.

2. Аналог TSQL-оператора IN

В Linq-To-SharePoint его нет, поэтому выражения вида:

using (var ctx = new HRDataContext(_webUrl))
{
  var vipIds = new [] { 1, 5, 9, 23, 57, 198, 345);
  var emps = ctx.EmployeeCollection.Where(e => vipIds.Contains(e.Id));
}

работать не будут. Вместо этого произойдет исключение. А чтобы его не было надо явно выгружать данные из списка в память (например .ToList()) и только потом использовать .Contains().

Вывод
использовать .Contains() только над коллекциями в памяти

3. Выбор данных из папки

По умолчанию Linq-to-SharePoint выбирает элементы списка/библиотеки только из корневого каталога. Чтобы заставить его вытащить данные из дочерних папок или из какой-то конкретной папки надо использовать метод .ScopeToFolder(rootFolder,recursiveFlag), где

  • **rootFolder **- папка, из которой выбираем данные (для корневой папки можно передать string.Empty);
  • recursiveFlag- флаг, определяющий просмотр дочерних папок (флаг поднят - смотрим, опущен - не обращаем внимание на дочерние папки)

Используем примерно так:

using (var ctx = new HRDataContext(_webUrl))
{
  string.Empty
  var emps = ctx.EmployeeCollection.ScopeToFolder(string.Empty);
}

Я рекомендовал бы при разработке сразу учитывать эту особенность и не ждать, пока пользователи начнут строить структуру папок внутри списка и удивляться, что система работает странновато.

Вывод
планировать возможность создания папок в списках/библиотеках и учитывать это при разработке.

4. Сохранение элемента в папке списка/библиотеки

Данные из папки выбирать научились, теперь надо бы уметь и сохранять/создавать элемент в папке. Для этого просто указываем путь к папке в свойстве Path элемента. Примерно вот так:

var query = ctx.DocumentCardCollection
        .ScopeToFolder(string.Empty, true)
        .Where(d => d.Date >= DateTime.Today.AddDays(-5));
var card = query.First();
card.Path = "/WebUrl/ListUrl/Folder1/SubFolder2";

Вывод
см. вывод в п.3

Пользуемся на здоровье и покоряем сердца заказчиков

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

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

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

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

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

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

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

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

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

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

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

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

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

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