English version

SharePoint + Reporting Services = нюансы

Я и мои коллеги занимаемся разработкой и внедрением прикладных внутрикорпоративных решений на базе платформы Microsoft SharePoint, а так же Российских СЭД, внедрение которых обосновано накопленным годами опытом и целесообразно в определенных случаях.

На своих проектах обожаю использовать Microsoft Reporting Services (далее - SSRS) для быстрой реализации отчетов и печатных форм, не требующих сложной динамики поведения.

При наличии доступности данных в структуре таблиц СУБД, а, следовательно, и DataSet отчета, с SSRS все легко и просто, если не сказать тривиально (естественно не для всех случаев). А что, если доступа к БД нет или же он запрещен лицензионной политикой или же даже применяются попытки сделать его технически сложно реализуемым? Надо готовить витрину данных средствами ETL. А что, если условия, бюджет и сроки проекта не допускают этого? Надо использовать доступные источники данных (DataSource).

Как можно было догадаться, речь пойдет о создании отчетов SSRS с ипользованием данных из списков SharePoint.

Арсенал доступных источников данных SSRS хоть и велик, но на практике можно «вляпаться» в нюансы, которые не всегда очевидны.

Итак, переходим к постановке задачи.

Исходные данные:

  • Информационная система на базе Microsoft SharePoint 2010 Foundation;
  • Microsoft SQL Server 2008 R2 (причем, R2 - принципиальное условие);
  • Microsoft SQL Server Reporting Services в режиме интеграции с SharePoint.

Постановка задачи:

  • Реализовать специализированный отчет, использующий данные, распределенные по нескольким различным спискам (Lists) SharePoint.
  • Не использовать витрины данных или кастомизированные веб-сервисы (их конечно можно использовать, но в рамки задачи и трудоемкость уже не влезает дополнительная разработка).

Казалось бы, что может быть проще? На практике может оказаться печаль.

К слову, для SharePoint прямое обращение к данным в БД технически возможно, да, но затруднено, и не разрешено лицензионной политикой. И, если честно, лучше даже и не пытаться напрямую получать доступ к объектам БД SharePoint, поверьте.

Ладно, продолжим. SQL Server 2008, начиная с версии R2, подарил нам новый источник данных в виде списков SharePoint. Чудно? Да как бы не всегда!

Проблема заключается в следующем:

  • Хотите Join в рамках одного DataSet? Забудьте.
  • Хотите получать данные из структуры папок в списке? Забудьте.

По поводу объединения различных списков в рамках одного DataSet. Да, это невозможно. DataSet, получающий данные из списка SharePoint может содержать только данные из одного списка. Как выход - для каждого списка создавать отдельный DataSet, хитрым образом фильтровать зависимые DataSet’ы через системные параметры SSRS отчета, чтобы не забирать весь массив данных по всем объединяемым спискам, и делать Join данных из различных списков с помощью функций SSRS (Lookup, LookupSet или MultiLookup) в самом представлении отчета, например, в таблице.

По второму пункту. В списках SharePoint есть такое понятие, как Throttling, когда задается ограничение количества элементов в папке, по умолчанию оно равняется 5К элементов. Что же обычно делается для больших списков? По-простому, структура хранения элементов меняется таким образом, чтобы в списке были папки (скрытые), а данные архивировались так, чтобы в каждой конкретной папке не было более 5К элементов или же того значения, что задан в настройках списка (по опыту – лучше пусть 5К и остается).

Мы как раз и имеем дело с таким списком, где элементов много, все по папкам, данные, прошедшие свой жизненный цикл архивируются, но остаются в списке и нужны, в том числе и для отчетов.

Казалось бы, в веб-сервис RSSharePointList, из которого получаются данные, встроен CAML и достаточно для обхода нюанса, но, к сожалению, скоуп в SharePoint List Datasource не внедрен. Просто-напросто такие данные с помощью Datasource «Список SharePoint» не получить никак.

Но данные нужны же и что-то надо делать, при этом не витрину, нет времени. Возвращаемся к истокам и смотрим в сторону получения данных через веб-сервисы SharePoint, но не те, о которых речь была выше. Создаем Datasource, используем тип соединения XML, в строку соединения пишем «путь до коллекции сайтов SharePoint»+«/_vti_bin/Lists.asmx», указываем учетные данные служебного пользователя для отчетов. Далее интереснее – создаем DataSet с источником, описанным выше и запросом на подобии:

<Query>

   <SoapAction>http://schemas.microsoft.com/sharepoint/soap/GetListItems</SoapAction>

   <Method Namespace='http://schemas.microsoft.com/sharepoint/soap/' Name='GetListItems'>

   <Parameters>

      <Parameter Name='listName'>

         <DefaultValue>{A4AA15E5-D722-4583-AA7D-C51C86A384F4}</DefaultValue>

      </Parameter>

      <Parameter Name='viewName'>

         <DefaultValue>{231A273A-DDA2-4CA1-B8FC-54B3DC4B0816}</DefaultValue>

      </Parameter>

      <Parameter Name='query' Type='xml'>

         <DefaultValue>

            <Query><Where> ... </Where></Query>

         </DefaultValue>

      </Parameter>

   </Parameters>

   <ElementPath IgnoreNamespaces='True'>*</ElementPath>

</Query>

Запрос можно формировать программно, например нужно отфильтровать только данные, которые получаются путем Inner Join с другим DataSet. И это можно, формируя динамически запрос и подставляя в него нужный фрагмент CAML-запроса.

Овладев парой-тройкой трюков получения данных и оказавшись в условиях схожих с условиями поставленной задачи, можно быстро реализовать довольно сложный отчет и задеплоить его для функционального заказчика, даже будучи в условиях ограниченных прав, когда доступ к SQL Server отсутствует и не достучаться до администратора фермы SharePoint.


Опубликовано: 23.04.2013
Автор: Андрей Кольтяков