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

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

Теги

Поделиться

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

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

Техлид, Архитектор, Разработчик, Microsoft MVP. Более 20 лет опыта в области системной интеграции и разработки программного обеспечения. Специализируюсь на проектировании и внедрении масштабируемых высокопроизводительных программных решений в различных отраслях.